diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 682f0d25c1431..acb30f2de5d00 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1348,7 +1348,7 @@ class Sema { void emit(const SemaDiagnosticBuilder &DB, llvm::index_sequence) const { // Apply all tuple elements to the builder in order. - bool Dummy[] = {(DB << getPrintable(std::get(Args)))...}; + bool Dummy[] = {false, (DB << getPrintable(std::get(Args)))...}; (void)Dummy; } @@ -1425,6 +1425,7 @@ class Sema { return RequireCompleteType(Loc, T, Diagnoser); } + void completeExprArrayBound(Expr *E); bool RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser); bool RequireCompleteExprType(Expr *E, unsigned DiagID); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 61eeedb130ad7..434fc7540cd76 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -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(cast(T)->getDecl()); + CXXRecordDecl *Class = + cast(cast(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(LexDC) && - AssociatedClasses.count(cast(LexDC))) { + AssociatedClasses.count(cast(LexDC)) && + isVisible(cast(DI))) { DeclaredInAssociatedClass = true; break; } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index a0fb1ea3db594..58949bfd44067 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -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(ToRecordType->getDecl())) { @@ -6685,7 +6681,8 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, // the set of member candidates is empty. if (const RecordType *T1Rec = T1->getAs()) { // 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; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 388d258488b85..f44b01f8ac34a 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -6366,6 +6366,50 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, } } +void Sema::completeExprArrayBound(Expr *E) { + if (DeclRefExpr *DRE = dyn_cast(E->IgnoreParens())) { + if (VarDecl *Var = dyn_cast(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(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(E->IgnoreParens())) { - if (VarDecl *Var = dyn_cast(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(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()) - 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(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()) { + bool Instantiated = false; + bool Diagnosed = false; if (ClassTemplateSpecializationDecl *ClassTemplateSpec = dyn_cast(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(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); } diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp index fd6b4f5a2b18e..ef4e4e420d04f 100644 --- a/clang/test/Modules/cxx-templates.cpp +++ b/clang/test/Modules/cxx-templates.cpp @@ -105,8 +105,8 @@ void g() { TemplateInstantiationVisibility tiv1; TemplateInstantiationVisibility tiv2; - TemplateInstantiationVisibility 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 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 tiv4; int &p = WithPartialSpecializationUse().f(); diff --git a/clang/test/Modules/hidden-definition.cpp b/clang/test/Modules/hidden-definition.cpp new file mode 100644 index 0000000000000..d06f9393458f7 --- /dev/null +++ b/clang/test/Modules/hidden-definition.cpp @@ -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'}} diff --git a/clang/test/Modules/submodules-merge-defs.cpp b/clang/test/Modules/submodules-merge-defs.cpp index 12e3cadd531f3..23d1f5cfb12b5 100644 --- a/clang/test/Modules/submodules-merge-defs.cpp +++ b/clang/test/Modules/submodules-merge-defs.cpp @@ -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().f(); // expected-error +{{must be imported}} -int pre_fg = F().g(); // expected-error +{{must be imported}} +int pre_fg = F().g(); // expected-error +{{must be imported}} expected-error 2{{expected}} // expected-note@defs.h:34 +{{here}} G::A pre_ga // expected-error +{{must be imported}} diff --git a/clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp b/clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp index e1a052cef64e7..4f3df277d912b 100644 --- a/clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp +++ b/clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp @@ -308,7 +308,7 @@ template struct B { struct NameFromBase { T m; }; }; // expected-no template struct C : A, B { 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) == 4, ""); // expected-note {{in instantiation of template class 'two_types_in_base::C' requested here}} +static_assert(sizeof(C) != 0, ""); // expected-note {{in instantiation of template class 'two_types_in_base::C' requested here}} } namespace type_and_decl_in_base {