mirror of https://github.com/microsoft/clang.git
[modules] Don't try to use the definition of a class if
RequireCompleteType(..., 0) says we're not permitted to do so. The definition might not be visible, even though we know what it is. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@256045 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e11f410f5c
commit
e8bff7792a
|
@ -1348,7 +1348,7 @@ public:
|
|||
void emit(const SemaDiagnosticBuilder &DB,
|
||||
llvm::index_sequence<Is...>) const {
|
||||
// Apply all tuple elements to the builder in order.
|
||||
bool Dummy[] = {(DB << getPrintable(std::get<Is>(Args)))...};
|
||||
bool Dummy[] = {false, (DB << getPrintable(std::get<Is>(Args)))...};
|
||||
(void)Dummy;
|
||||
}
|
||||
|
||||
|
@ -1425,6 +1425,7 @@ public:
|
|||
return RequireCompleteType(Loc, T, Diagnoser);
|
||||
}
|
||||
|
||||
void completeExprArrayBound(Expr *E);
|
||||
bool RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser);
|
||||
bool RequireCompleteExprType(Expr *E, unsigned DiagID);
|
||||
|
||||
|
|
|
@ -2428,7 +2428,8 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
|
|||
}
|
||||
|
||||
// Only recurse into base classes for complete types.
|
||||
if (!Class->hasDefinition())
|
||||
if (Result.S.RequireCompleteType(Result.InstantiationLoc,
|
||||
Result.S.Context.getRecordType(Class), 0))
|
||||
return;
|
||||
|
||||
// Add direct and indirect base classes along with their associated
|
||||
|
@ -2521,10 +2522,8 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
|
|||
// classes. Its associated namespaces are the namespaces in
|
||||
// which its associated classes are defined.
|
||||
case Type::Record: {
|
||||
Result.S.RequireCompleteType(Result.InstantiationLoc, QualType(T, 0),
|
||||
/*no diagnostic*/ 0);
|
||||
CXXRecordDecl *Class
|
||||
= cast<CXXRecordDecl>(cast<RecordType>(T)->getDecl());
|
||||
CXXRecordDecl *Class =
|
||||
cast<CXXRecordDecl>(cast<RecordType>(T)->getDecl());
|
||||
addAssociatedClassesAndNamespaces(Result, Class);
|
||||
break;
|
||||
}
|
||||
|
@ -3208,7 +3207,8 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
|
|||
for (Decl *DI = D; DI; DI = DI->getPreviousDecl()) {
|
||||
DeclContext *LexDC = DI->getLexicalDeclContext();
|
||||
if (isa<CXXRecordDecl>(LexDC) &&
|
||||
AssociatedClasses.count(cast<CXXRecordDecl>(LexDC))) {
|
||||
AssociatedClasses.count(cast<CXXRecordDecl>(LexDC)) &&
|
||||
isVisible(cast<NamedDecl>(DI))) {
|
||||
DeclaredInAssociatedClass = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -3085,11 +3085,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
|
|||
S.IsDerivedFrom(From->getLocStart(), From->getType(), ToType)))
|
||||
ConstructorsOnly = true;
|
||||
|
||||
S.RequireCompleteType(From->getExprLoc(), ToType, 0);
|
||||
// RequireCompleteType may have returned true due to some invalid decl
|
||||
// during template instantiation, but ToType may be complete enough now
|
||||
// to try to recover.
|
||||
if (ToType->isIncompleteType()) {
|
||||
if (S.RequireCompleteType(From->getExprLoc(), ToType, 0)) {
|
||||
// We're not going to find any constructors.
|
||||
} else if (CXXRecordDecl *ToRecordDecl
|
||||
= dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) {
|
||||
|
@ -6685,7 +6681,8 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
|
|||
// the set of member candidates is empty.
|
||||
if (const RecordType *T1Rec = T1->getAs<RecordType>()) {
|
||||
// Complete the type if it can be completed.
|
||||
RequireCompleteType(OpLoc, T1, 0);
|
||||
if (RequireCompleteType(OpLoc, T1, 0) && !T1Rec->isBeingDefined())
|
||||
return;
|
||||
// If the type is neither complete nor being defined, bail out now.
|
||||
if (!T1Rec->getDecl()->getDefinition())
|
||||
return;
|
||||
|
|
|
@ -6366,6 +6366,50 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
|
|||
}
|
||||
}
|
||||
|
||||
void Sema::completeExprArrayBound(Expr *E) {
|
||||
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
|
||||
if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
|
||||
if (isTemplateInstantiation(Var->getTemplateSpecializationKind())) {
|
||||
SourceLocation PointOfInstantiation = E->getExprLoc();
|
||||
|
||||
if (MemberSpecializationInfo *MSInfo =
|
||||
Var->getMemberSpecializationInfo()) {
|
||||
// If we don't already have a point of instantiation, this is it.
|
||||
if (MSInfo->getPointOfInstantiation().isInvalid()) {
|
||||
MSInfo->setPointOfInstantiation(PointOfInstantiation);
|
||||
|
||||
// This is a modification of an existing AST node. Notify
|
||||
// listeners.
|
||||
if (ASTMutationListener *L = getASTMutationListener())
|
||||
L->StaticDataMemberInstantiated(Var);
|
||||
}
|
||||
} else {
|
||||
VarTemplateSpecializationDecl *VarSpec =
|
||||
cast<VarTemplateSpecializationDecl>(Var);
|
||||
if (VarSpec->getPointOfInstantiation().isInvalid())
|
||||
VarSpec->setPointOfInstantiation(PointOfInstantiation);
|
||||
}
|
||||
|
||||
InstantiateVariableDefinition(PointOfInstantiation, Var);
|
||||
|
||||
// Update the type to the newly instantiated definition's type both
|
||||
// here and within the expression.
|
||||
if (VarDecl *Def = Var->getDefinition()) {
|
||||
DRE->setDecl(Def);
|
||||
QualType T = Def->getType();
|
||||
DRE->setType(T);
|
||||
// FIXME: Update the type on all intervening expressions.
|
||||
E->setType(T);
|
||||
}
|
||||
|
||||
// We still go on to try to complete the type independently, as it
|
||||
// may also require instantiations or diagnostics if it remains
|
||||
// incomplete.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Ensure that the type of the given expression is complete.
|
||||
///
|
||||
/// This routine checks whether the expression \p E has a complete type. If the
|
||||
|
@ -6380,87 +6424,26 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
|
|||
///
|
||||
/// \returns \c true if the type of \p E is incomplete and diagnosed, \c false
|
||||
/// otherwise.
|
||||
bool Sema::RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser){
|
||||
bool Sema::RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser) {
|
||||
QualType T = E->getType();
|
||||
|
||||
// Fast path the case where the type is already complete.
|
||||
if (!T->isIncompleteType())
|
||||
// FIXME: The definition might not be visible.
|
||||
return false;
|
||||
|
||||
// Incomplete array types may be completed by the initializer attached to
|
||||
// their definitions. For static data members of class templates and for
|
||||
// variable templates, we need to instantiate the definition to get this
|
||||
// initializer and complete the type.
|
||||
if (T->isIncompleteArrayType()) {
|
||||
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
|
||||
if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
|
||||
if (isTemplateInstantiation(Var->getTemplateSpecializationKind())) {
|
||||
SourceLocation PointOfInstantiation = E->getExprLoc();
|
||||
|
||||
if (MemberSpecializationInfo *MSInfo =
|
||||
Var->getMemberSpecializationInfo()) {
|
||||
// If we don't already have a point of instantiation, this is it.
|
||||
if (MSInfo->getPointOfInstantiation().isInvalid()) {
|
||||
MSInfo->setPointOfInstantiation(PointOfInstantiation);
|
||||
|
||||
// This is a modification of an existing AST node. Notify
|
||||
// listeners.
|
||||
if (ASTMutationListener *L = getASTMutationListener())
|
||||
L->StaticDataMemberInstantiated(Var);
|
||||
}
|
||||
} else {
|
||||
VarTemplateSpecializationDecl *VarSpec =
|
||||
cast<VarTemplateSpecializationDecl>(Var);
|
||||
if (VarSpec->getPointOfInstantiation().isInvalid())
|
||||
VarSpec->setPointOfInstantiation(PointOfInstantiation);
|
||||
}
|
||||
|
||||
InstantiateVariableDefinition(PointOfInstantiation, Var);
|
||||
|
||||
// Update the type to the newly instantiated definition's type both
|
||||
// here and within the expression.
|
||||
if (VarDecl *Def = Var->getDefinition()) {
|
||||
DRE->setDecl(Def);
|
||||
T = Def->getType();
|
||||
DRE->setType(T);
|
||||
E->setType(T);
|
||||
}
|
||||
|
||||
// We still go on to try to complete the type independently, as it
|
||||
// may also require instantiations or diagnostics if it remains
|
||||
// incomplete.
|
||||
}
|
||||
}
|
||||
}
|
||||
completeExprArrayBound(E);
|
||||
T = E->getType();
|
||||
}
|
||||
|
||||
// FIXME: Are there other cases which require instantiating something other
|
||||
// than the type to complete the type of an expression?
|
||||
|
||||
// Look through reference types and complete the referred type.
|
||||
if (const ReferenceType *Ref = T->getAs<ReferenceType>())
|
||||
T = Ref->getPointeeType();
|
||||
|
||||
return RequireCompleteType(E->getExprLoc(), T, Diagnoser);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct TypeDiagnoserDiag : Sema::TypeDiagnoser {
|
||||
unsigned DiagID;
|
||||
|
||||
TypeDiagnoserDiag(unsigned DiagID)
|
||||
: Sema::TypeDiagnoser(DiagID == 0), DiagID(DiagID) {}
|
||||
|
||||
void diagnose(Sema &S, SourceLocation Loc, QualType T) override {
|
||||
if (Suppressed) return;
|
||||
S.Diag(Loc, DiagID) << T;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool Sema::RequireCompleteExprType(Expr *E, unsigned DiagID) {
|
||||
TypeDiagnoserDiag Diagnoser(DiagID);
|
||||
BoundTypeDiagnoser<> Diagnoser(DiagID);
|
||||
return RequireCompleteExprType(E, Diagnoser);
|
||||
}
|
||||
|
||||
|
@ -6612,9 +6595,16 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
|
|||
if (!T->isIncompleteType(&Def)) {
|
||||
// If we know about the definition but it is not visible, complain.
|
||||
NamedDecl *SuggestedDef = nullptr;
|
||||
if (!Diagnoser.Suppressed && Def &&
|
||||
!hasVisibleDefinition(Def, &SuggestedDef, /*OnlyNeedComplete*/true))
|
||||
diagnoseMissingImport(Loc, SuggestedDef, /*NeedDefinition*/true);
|
||||
if (Def &&
|
||||
!hasVisibleDefinition(Def, &SuggestedDef, /*OnlyNeedComplete*/true)) {
|
||||
// If the user is going to see an error here, recover by making the
|
||||
// definition visible.
|
||||
bool TreatAsComplete = !Diagnoser.Suppressed && !isSFINAEContext();
|
||||
if (!Diagnoser.Suppressed)
|
||||
diagnoseMissingImport(Loc, SuggestedDef, /*NeedDefinition*/true,
|
||||
/*Recover*/TreatAsComplete);
|
||||
return !TreatAsComplete;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -6630,6 +6620,9 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
|
|||
// chain for a declaration that can be accessed through a mechanism other
|
||||
// than name lookup (eg, referenced in a template, or a variable whose type
|
||||
// could be completed by the module)?
|
||||
//
|
||||
// FIXME: Should we map through to the base array element type before
|
||||
// checking for a tag type?
|
||||
if (Tag || IFace) {
|
||||
NamedDecl *D =
|
||||
Tag ? static_cast<NamedDecl *>(Tag->getDecl()) : IFace->getDecl();
|
||||
|
@ -6660,12 +6653,16 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
|
|||
= Context.getAsConstantArrayType(MaybeTemplate))
|
||||
MaybeTemplate = Array->getElementType();
|
||||
if (const RecordType *Record = MaybeTemplate->getAs<RecordType>()) {
|
||||
bool Instantiated = false;
|
||||
bool Diagnosed = false;
|
||||
if (ClassTemplateSpecializationDecl *ClassTemplateSpec
|
||||
= dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) {
|
||||
if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared)
|
||||
return InstantiateClassTemplateSpecialization(Loc, ClassTemplateSpec,
|
||||
TSK_ImplicitInstantiation,
|
||||
/*Complain=*/!Diagnoser.Suppressed);
|
||||
if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) {
|
||||
Diagnosed = InstantiateClassTemplateSpecialization(
|
||||
Loc, ClassTemplateSpec, TSK_ImplicitInstantiation,
|
||||
/*Complain=*/!Diagnoser.Suppressed);
|
||||
Instantiated = true;
|
||||
}
|
||||
} else if (CXXRecordDecl *Rec
|
||||
= dyn_cast<CXXRecordDecl>(Record->getDecl())) {
|
||||
CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass();
|
||||
|
@ -6673,13 +6670,28 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
|
|||
MemberSpecializationInfo *MSI = Rec->getMemberSpecializationInfo();
|
||||
assert(MSI && "Missing member specialization information?");
|
||||
// This record was instantiated from a class within a template.
|
||||
if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
|
||||
return InstantiateClass(Loc, Rec, Pattern,
|
||||
getTemplateInstantiationArgs(Rec),
|
||||
TSK_ImplicitInstantiation,
|
||||
/*Complain=*/!Diagnoser.Suppressed);
|
||||
if (MSI->getTemplateSpecializationKind() !=
|
||||
TSK_ExplicitSpecialization) {
|
||||
Diagnosed = InstantiateClass(Loc, Rec, Pattern,
|
||||
getTemplateInstantiationArgs(Rec),
|
||||
TSK_ImplicitInstantiation,
|
||||
/*Complain=*/!Diagnoser.Suppressed);
|
||||
Instantiated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Instantiated) {
|
||||
// Instantiate* might have already complained that the template is not
|
||||
// defined, if we asked it to.
|
||||
if (!Diagnoser.Suppressed && Diagnosed)
|
||||
return true;
|
||||
// If we instantiated a definition, check that it's usable, even if
|
||||
// instantiation produced an error, so that repeated calls to this
|
||||
// function give consistent answers.
|
||||
if (!T->isIncompleteType())
|
||||
return RequireCompleteTypeImpl(Loc, T, Diagnoser);
|
||||
}
|
||||
}
|
||||
|
||||
if (Diagnoser.Suppressed)
|
||||
|
@ -6716,7 +6728,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
|
|||
|
||||
bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
|
||||
unsigned DiagID) {
|
||||
TypeDiagnoserDiag Diagnoser(DiagID);
|
||||
BoundTypeDiagnoser<> Diagnoser(DiagID);
|
||||
return RequireCompleteType(Loc, T, Diagnoser);
|
||||
}
|
||||
|
||||
|
@ -6757,14 +6769,10 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
|
|||
assert(!T->isDependentType() && "type should not be dependent");
|
||||
|
||||
QualType ElemType = Context.getBaseElementType(T);
|
||||
RequireCompleteType(Loc, ElemType, 0);
|
||||
|
||||
if (T->isLiteralType(Context))
|
||||
if ((!RequireCompleteType(Loc, ElemType, 0) || ElemType->isVoidType()) &&
|
||||
T->isLiteralType(Context))
|
||||
return false;
|
||||
|
||||
if (Diagnoser.Suppressed)
|
||||
return true;
|
||||
|
||||
Diagnoser.diagnose(*this, Loc, T);
|
||||
|
||||
if (T->isVariableArrayType())
|
||||
|
@ -6779,10 +6787,8 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
|
|||
// A partially-defined class type can't be a literal type, because a literal
|
||||
// class type must have a trivial destructor (which can't be checked until
|
||||
// the class definition is complete).
|
||||
if (!RD->isCompleteDefinition()) {
|
||||
RequireCompleteType(Loc, ElemType, diag::note_non_literal_incomplete, T);
|
||||
if (RequireCompleteType(Loc, ElemType, diag::note_non_literal_incomplete, T))
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the class has virtual base classes, then it's not an aggregate, and
|
||||
// cannot have any constexpr constructors or a trivial default constructor,
|
||||
|
@ -6834,7 +6840,7 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
|
|||
}
|
||||
|
||||
bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID) {
|
||||
TypeDiagnoserDiag Diagnoser(DiagID);
|
||||
BoundTypeDiagnoser<> Diagnoser(DiagID);
|
||||
return RequireLiteralType(Loc, T, Diagnoser);
|
||||
}
|
||||
|
||||
|
|
|
@ -105,8 +105,8 @@ void g() {
|
|||
|
||||
TemplateInstantiationVisibility<char[1]> tiv1;
|
||||
TemplateInstantiationVisibility<char[2]> tiv2;
|
||||
TemplateInstantiationVisibility<char[3]> tiv3; // expected-error {{must be imported from module 'cxx_templates_b_impl'}}
|
||||
// expected-note@cxx-templates-b-impl.h:10 {{previous definition is here}}
|
||||
TemplateInstantiationVisibility<char[3]> tiv3; // expected-error 2{{must be imported from module 'cxx_templates_b_impl'}}
|
||||
// expected-note@cxx-templates-b-impl.h:10 2{{previous definition is here}}
|
||||
TemplateInstantiationVisibility<char[4]> tiv4;
|
||||
|
||||
int &p = WithPartialSpecializationUse().f();
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// RUN: rm -rf %t
|
||||
// RUN: mkdir %t
|
||||
// RUN: echo 'struct X {}; struct Y : X { friend int f(Y); };' > %t/a.h
|
||||
// RUN: echo 'module a { header "a.h" }' > %t/map
|
||||
// RUN: %clang_cc1 -fmodules -x c++ -emit-module -fmodule-name=a %t/map -o %t/a.pcm
|
||||
// RUN: %clang_cc1 -fmodules -x c++ -verify -fmodule-file=%t/a.pcm %s -fno-modules-error-recovery
|
||||
|
||||
struct X;
|
||||
struct Y;
|
||||
|
||||
// Ensure that we can't use the definitions of X and Y, since we've not imported module a.
|
||||
Y *yp;
|
||||
X *xp = yp; // expected-error {{cannot initialize}}
|
||||
_Static_assert(!__is_convertible(Y*, X*), "");
|
||||
X &xr = *yp; // expected-error {{unrelated type}}
|
||||
int g(Y &y) { f(y); } // expected-error {{undeclared identifier 'f'}}
|
|
@ -22,7 +22,7 @@ A pre_a;
|
|||
#endif
|
||||
// expected-note@defs.h:1 +{{here}}
|
||||
extern class A pre_a2;
|
||||
int pre_use_a = use_a(pre_a2); // expected-error {{'A' must be imported}} expected-error {{'use_a' must be imported}}
|
||||
int pre_use_a = use_a(pre_a2); // expected-error 2{{'A' must be imported}} expected-error {{'use_a' must be imported}}
|
||||
// expected-note@defs.h:2 +{{here}}
|
||||
|
||||
B::Inner2 pre_bi; // expected-error +{{must be imported}}
|
||||
|
@ -48,7 +48,7 @@ int pre_e = E(0); // expected-error {{must be imported}}
|
|||
// expected-note@defs.h:32 +{{here}}
|
||||
|
||||
int pre_ff = F<int>().f(); // expected-error +{{must be imported}}
|
||||
int pre_fg = F<int>().g<int>(); // expected-error +{{must be imported}}
|
||||
int pre_fg = F<int>().g<int>(); // expected-error +{{must be imported}} expected-error 2{{expected}}
|
||||
// expected-note@defs.h:34 +{{here}}
|
||||
|
||||
G::A pre_ga // expected-error +{{must be imported}}
|
||||
|
|
|
@ -308,7 +308,7 @@ template <typename T> struct B { struct NameFromBase { T m; }; }; // expected-no
|
|||
template <typename T> struct C : A<T>, B<T> {
|
||||
NameFromBase m; // expected-error {{member 'NameFromBase' found in multiple base classes of different types}} expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
|
||||
};
|
||||
static_assert(sizeof(C<int>) == 4, ""); // expected-note {{in instantiation of template class 'two_types_in_base::C<int>' requested here}}
|
||||
static_assert(sizeof(C<int>) != 0, ""); // expected-note {{in instantiation of template class 'two_types_in_base::C<int>' requested here}}
|
||||
}
|
||||
|
||||
namespace type_and_decl_in_base {
|
||||
|
|
Loading…
Reference in New Issue