diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-05-05 00:56:12 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-05-05 00:56:12 +0000 |
| commit | 6739a10cec3d5681cc1c0f793be58756dfe0537a (patch) | |
| tree | e2742beb3f5a7c2dd218150a1deeaebee1005f18 /clang/lib | |
| parent | d55bc4c7abeff02a8641918dfa65cac16d9c8818 (diff) | |
| download | bcm5719-llvm-6739a10cec3d5681cc1c0f793be58756dfe0537a.tar.gz bcm5719-llvm-6739a10cec3d5681cc1c0f793be58756dfe0537a.zip | |
[modules] Enforce the rules that an explicit or partial specialization must be
declared before it is used. Because we don't use normal name lookup to find
these, the normal code to filter out non-visible names from name lookup results
does not apply.
llvm-svn: 268585
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/Decl.cpp | 15 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaCXXScopeSpec.cpp | 31 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 87 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 75 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 158 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 15 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 20 |
8 files changed, 350 insertions, 59 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 9246f94e845..98bc36bbbdd 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3687,6 +3687,21 @@ void EnumDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, MSI->setPointOfInstantiation(PointOfInstantiation); } +EnumDecl *EnumDecl::getTemplateInstantiationPattern() const { + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { + if (isTemplateInstantiation(MSInfo->getTemplateSpecializationKind())) { + EnumDecl *ED = getInstantiatedFromMemberEnum(); + while (auto *NewED = ED->getInstantiatedFromMemberEnum()) + ED = NewED; + return ED; + } + } + + assert(!isTemplateInstantiation(getTemplateSpecializationKind()) && + "couldn't find pattern for enum instantiation"); + return nullptr; +} + EnumDecl *EnumDecl::getInstantiatedFromMemberEnum() const { if (SpecializationInfo) return cast<EnumDecl>(SpecializationInfo->getInstantiatedFrom()); diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 2e774dd28ce..ab0e709a97e 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -117,8 +117,18 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, // specializations, we're entering into the definition of that // class template partial specialization. if (ClassTemplatePartialSpecializationDecl *PartialSpec - = ClassTemplate->findPartialSpecialization(ContextType)) + = ClassTemplate->findPartialSpecialization(ContextType)) { + // A declaration of the partial specialization must be visible. + // We can always recover here, because this only happens when we're + // entering the context, and that can't happen in a SFINAE context. + assert(!isSFINAEContext() && + "partial specialization scope specifier in SFINAE context?"); + if (!hasVisibleDeclaration(PartialSpec)) + diagnoseMissingImport(SS.getLastQualifierNameLoc(), PartialSpec, + MissingImportKind::PartialSpecialization, + /*Recover*/true); return PartialSpec; + } } } else if (const RecordType *RecordT = NNSType->getAs<RecordType>()) { // The nested name specifier refers to a member of a class template. @@ -195,6 +205,8 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, TagDecl *tag = dyn_cast<TagDecl>(DC); // If this is a dependent type, then we consider it complete. + // FIXME: This is wrong; we should require a (visible) definition to + // exist in this case too. if (!tag || tag->isDependentContext()) return false; @@ -218,10 +230,23 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, // Fixed enum types are complete, but they aren't valid as scopes // until we see a definition, so awkwardly pull out this special // case. - // FIXME: The definition might not be visible; complain if it is not. const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType); - if (!enumType || enumType->getDecl()->isCompleteDefinition()) + if (!enumType) return false; + if (enumType->getDecl()->isCompleteDefinition()) { + // If we know about the definition but it is not visible, complain. + NamedDecl *SuggestedDef = nullptr; + if (!hasVisibleDefinition(enumType->getDecl(), &SuggestedDef, + /*OnlyNeedComplete*/false)) { + // If the user is going to see an error here, recover by making the + // definition visible. + bool TreatAsComplete = !isSFINAEContext(); + diagnoseMissingImport(loc, SuggestedDef, MissingImportKind::Definition, + /*Recover*/TreatAsComplete); + return !TreatAsComplete; + } + return false; + } // Try to instantiate the definition, if this is a specialization of an // enumeration temploid. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 6b043368db1..2b89b6bd039 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -12859,39 +12859,53 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // set of overloaded functions [...]. // // We (incorrectly) mark overload resolution as an unevaluated context, so we - // can just check that here. Skip the rest of this function if we've already - // marked the function as used. + // can just check that here. bool OdrUse = MightBeOdrUse && IsPotentiallyEvaluatedContext(*this); - if (Func->isUsed(/*CheckUsedAttr=*/false) || !OdrUse) { - // C++11 [temp.inst]p3: - // Unless a function template specialization has been explicitly - // instantiated or explicitly specialized, the function template - // specialization is implicitly instantiated when the specialization is - // referenced in a context that requires a function definition to exist. - // - // We consider constexpr function templates to be referenced in a context - // that requires a definition to exist whenever they are referenced. - // - // FIXME: This instantiates constexpr functions too frequently. If this is - // really an unevaluated context (and we're not just in the definition of a - // function template or overload resolution or other cases which we - // incorrectly consider to be unevaluated contexts), and we're not in a - // subexpression which we actually need to evaluate (for instance, a - // template argument, array bound or an expression in a braced-init-list), - // we are not permitted to instantiate this constexpr function definition. - // - // FIXME: This also implicitly defines special members too frequently. They - // are only supposed to be implicitly defined if they are odr-used, but they - // are not odr-used from constant expressions in unevaluated contexts. - // However, they cannot be referenced if they are deleted, and they are - // deleted whenever the implicit definition of the special member would - // fail. - if (!Func->isConstexpr() || Func->getBody()) - return; - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func); - if (!Func->isImplicitlyInstantiable() && (!MD || MD->isUserProvided())) - return; - } + + // Determine whether we require a function definition to exist, per + // C++11 [temp.inst]p3: + // Unless a function template specialization has been explicitly + // instantiated or explicitly specialized, the function template + // specialization is implicitly instantiated when the specialization is + // referenced in a context that requires a function definition to exist. + // + // We consider constexpr function templates to be referenced in a context + // that requires a definition to exist whenever they are referenced. + // + // FIXME: This instantiates constexpr functions too frequently. If this is + // really an unevaluated context (and we're not just in the definition of a + // function template or overload resolution or other cases which we + // incorrectly consider to be unevaluated contexts), and we're not in a + // subexpression which we actually need to evaluate (for instance, a + // template argument, array bound or an expression in a braced-init-list), + // we are not permitted to instantiate this constexpr function definition. + // + // FIXME: This also implicitly defines special members too frequently. They + // are only supposed to be implicitly defined if they are odr-used, but they + // are not odr-used from constant expressions in unevaluated contexts. + // However, they cannot be referenced if they are deleted, and they are + // deleted whenever the implicit definition of the special member would + // fail (with very few exceptions). + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func); + bool NeedDefinition = + OdrUse || (Func->isConstexpr() && (Func->isImplicitlyInstantiable() || + (MD && !MD->isUserProvided()))); + + // C++14 [temp.expl.spec]p6: + // If a template [...] is explicitly specialized then that specialization + // shall be declared before the first use of that specialization that would + // cause an implicit instantiation to take place, in every translation unit + // in which such a use occurs + if (NeedDefinition && + (Func->getTemplateSpecializationKind() != TSK_Undeclared || + Func->getMemberSpecializationInfo())) + checkSpecializationVisibility(Loc, Func); + + // If we don't need to mark the function as used, and we don't need to + // try to provide a definition, there's nothing more to do. + if ((Func->isUsed(/*CheckUsedAttr=*/false) || !OdrUse) && + (!NeedDefinition || Func->getBody())) + return; // Note that this declaration has been used. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) { @@ -13797,6 +13811,12 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, assert(!isa<VarTemplatePartialSpecializationDecl>(Var) && "Can't instantiate a partial template specialization."); + // If this might be a member specialization of a static data member, check + // the specialization is visible. We already did the checks for variable + // template specializations when we created them. + if (TSK != TSK_Undeclared && !isa<VarTemplateSpecializationDecl>(Var)) + SemaRef.checkSpecializationVisibility(Loc, Var); + // Perform implicit instantiation of static data members, static data member // templates of class templates, and variable template specializations. Delay // instantiations of variable templates, except for those that could be used @@ -13840,7 +13860,8 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, } } - if(!MarkODRUsed) return; + if (!MarkODRUsed) + return; // Per C++11 [basic.def.odr], a variable is odr-used "unless it satisfies // the requirements for appearing in a constant expression (5.19) and, if diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 66e3601f047..eaf44861d32 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1482,6 +1482,35 @@ bool Sema::hasVisibleDefaultArgument(const NamedDecl *D, Modules); } +bool Sema::hasVisibleMemberSpecialization( + const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) { + assert(isa<CXXRecordDecl>(D->getDeclContext()) && + "not a member specialization"); + for (auto *Redecl : D->redecls()) { + // If the specialization is declared at namespace scope, then it's a member + // specialization declaration. If it's lexically inside the class + // definition then it was instantiated. + // + // FIXME: This is a hack. There should be a better way to determine this. + // FIXME: What about MS-style explicit specializations declared within a + // class definition? + if (Redecl->getLexicalDeclContext()->isFileContext()) { + auto *NonConstR = const_cast<NamedDecl*>(cast<NamedDecl>(Redecl)); + + if (isVisible(NonConstR)) + return true; + + if (Modules) { + Modules->push_back(getOwningModule(NonConstR)); + const auto &Merged = Context.getModulesWithMergedDefinition(NonConstR); + Modules->insert(Modules->end(), Merged.begin(), Merged.end()); + } + } + } + + return false; +} + /// \brief Determine whether a declaration is visible to name lookup. /// /// This routine determines whether the declaration D is visible in the current @@ -1586,18 +1615,36 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) { if (RD == D) continue; - if (auto ND = dyn_cast<NamedDecl>(RD)) { - // FIXME: This is wrong in the case where the previous declaration is not - // visible in the same scope as D. This needs to be done much more - // carefully. - if (LookupResult::isVisible(SemaRef, ND)) - return ND; - } + auto ND = cast<NamedDecl>(RD); + // FIXME: This is wrong in the case where the previous declaration is not + // visible in the same scope as D. This needs to be done much more + // carefully. + if (LookupResult::isVisible(SemaRef, ND)) + return ND; } return nullptr; } +bool Sema::hasVisibleDeclarationSlow(const NamedDecl *D, + llvm::SmallVectorImpl<Module *> *Modules) { + assert(!isVisible(D) && "not in slow case"); + + for (auto *Redecl : D->redecls()) { + auto *NonConstR = const_cast<NamedDecl*>(cast<NamedDecl>(Redecl)); + if (isVisible(NonConstR)) + return true; + + if (Modules) { + Modules->push_back(getOwningModule(NonConstR)); + const auto &Merged = Context.getModulesWithMergedDefinition(NonConstR); + Modules->insert(Modules->end(), Merged.begin(), Merged.end()); + } + } + + return false; +} + NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const { if (auto *ND = dyn_cast<NamespaceDecl>(D)) { // Namespaces are a bit of a special case: we expect there to be a lot of @@ -4904,7 +4951,7 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) { } void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, - bool NeedDefinition, bool Recover) { + MissingImportKind MIK, bool Recover) { assert(!isVisible(Decl) && "missing import for non-hidden decl?"); // Suggest importing a module providing the definition of this entity, if @@ -4923,9 +4970,7 @@ void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, auto Merged = Context.getModulesWithMergedDefinition(Decl); OwningModules.insert(OwningModules.end(), Merged.begin(), Merged.end()); - diagnoseMissingImport(Loc, Decl, Decl->getLocation(), OwningModules, - NeedDefinition ? MissingImportKind::Definition - : MissingImportKind::Declaration, + diagnoseMissingImport(Loc, Decl, Decl->getLocation(), OwningModules, MIK, Recover); } @@ -4985,6 +5030,12 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, case MissingImportKind::DefaultArgument: DiagID = diag::note_default_argument_declared_here; break; + case MissingImportKind::ExplicitSpecialization: + DiagID = diag::note_explicit_specialization_declared_here; + break; + case MissingImportKind::PartialSpecialization: + DiagID = diag::note_partial_specialization_declared_here; + break; } Diag(DeclLoc, DiagID); @@ -5020,7 +5071,7 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, assert(Decl && "import required but no declaration to import"); diagnoseMissingImport(Correction.getCorrectionRange().getBegin(), Decl, - /*NeedDefinition*/ false, ErrorRecovery); + MissingImportKind::Declaration, ErrorRecovery); return; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 9d3bf1c1605..4960a2d1440 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2746,9 +2746,11 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, // corresponds to these arguments. void *InsertPos = nullptr; if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization( - Converted, InsertPos)) + Converted, InsertPos)) { + checkSpecializationVisibility(TemplateNameLoc, Spec); // If we already have a variable template specialization, return it. return Spec; + } // This is the first time we have referenced this variable template // specialization. Create the canonical declaration and add it to @@ -2847,8 +2849,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, } // 2. Create the canonical declaration. - // Note that we do not instantiate the variable just yet, since - // instantiation is handled in DoMarkVarDeclReferenced(). + // Note that we do not instantiate a definition until we see an odr-use + // in DoMarkVarDeclReferenced(). // FIXME: LateAttrs et al.? VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation( Template, InstantiationPattern, *InstantiationArgs, TemplateArgs, @@ -2876,6 +2878,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, dyn_cast<VarTemplatePartialSpecializationDecl>(InstantiationPattern)) Decl->setInstantiationOf(D, InstantiationArgs); + checkSpecializationVisibility(TemplateNameLoc, Decl); + assert(Decl && "No variable template specialization?"); return Decl; } @@ -3741,7 +3745,7 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc, S.diagnoseMissingImport(Loc, cast<NamedDecl>(TD), D->getDefaultArgumentLoc(), Modules, Sema::MissingImportKind::DefaultArgument, - /*Recover*/ true); + /*Recover*/true); return true; } @@ -8544,3 +8548,149 @@ bool Sema::IsInsideALocalClassWithinATemplateFunction() { } return false; } + +/// \brief Walk the path from which a declaration was instantiated, and check +/// that every explicit specialization along that path is visible. This enforces +/// C++ [temp.expl.spec]/6: +/// +/// If a template, a member template or a member of a class template is +/// explicitly specialized then that specialization shall be declared before +/// the first use of that specialization that would cause an implicit +/// instantiation to take place, in every translation unit in which such a +/// use occurs; no diagnostic is required. +/// +/// and also C++ [temp.class.spec]/1: +/// +/// A partial specialization shall be declared before the first use of a +/// class template specialization that would make use of the partial +/// specialization as the result of an implicit or explicit instantiation +/// in every translation unit in which such a use occurs; no diagnostic is +/// required. +class ExplicitSpecializationVisibilityChecker { + Sema &S; + SourceLocation Loc; + llvm::SmallVector<Module *, 8> Modules; + +public: + ExplicitSpecializationVisibilityChecker(Sema &S, SourceLocation Loc) + : S(S), Loc(Loc) {} + + void check(NamedDecl *ND) { + if (auto *FD = dyn_cast<FunctionDecl>(ND)) + return checkImpl(FD); + if (auto *RD = dyn_cast<CXXRecordDecl>(ND)) + return checkImpl(RD); + if (auto *VD = dyn_cast<VarDecl>(ND)) + return checkImpl(VD); + if (auto *ED = dyn_cast<EnumDecl>(ND)) + return checkImpl(ED); + } + +private: + void diagnose(NamedDecl *D, bool IsPartialSpec) { + auto Kind = IsPartialSpec ? Sema::MissingImportKind::PartialSpecialization + : Sema::MissingImportKind::ExplicitSpecialization; + const bool Recover = true; + + // If we got a custom set of modules (because only a subset of the + // declarations are interesting), use them, otherwise let + // diagnoseMissingImport intelligently pick some. + if (Modules.empty()) + S.diagnoseMissingImport(Loc, D, Kind, Recover); + else + S.diagnoseMissingImport(Loc, D, D->getLocation(), Modules, Kind, Recover); + } + + // Check a specific declaration. There are three problematic cases: + // + // 1) The declaration is an explicit specialization of a template + // specialization. + // 2) The declaration is an explicit specialization of a member of an + // templated class. + // 3) The declaration is an instantiation of a template, and that template + // is an explicit specialization of a member of a templated class. + // + // We don't need to go any deeper than that, as the instantiation of the + // surrounding class / etc is not triggered by whatever triggered this + // instantiation, and thus should be checked elsewhere. + template<typename SpecDecl> + void checkImpl(SpecDecl *Spec) { + bool IsHiddenExplicitSpecialization = false; + if (Spec->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { + IsHiddenExplicitSpecialization = + Spec->getMemberSpecializationInfo() + ? !S.hasVisibleMemberSpecialization(Spec, &Modules) + : !S.hasVisibleDeclaration(Spec); + } else { + checkInstantiated(Spec); + } + + if (IsHiddenExplicitSpecialization) + diagnose(Spec->getMostRecentDecl(), false); + } + + void checkInstantiated(FunctionDecl *FD) { + if (auto *TD = FD->getPrimaryTemplate()) + checkTemplate(TD); + } + + void checkInstantiated(CXXRecordDecl *RD) { + auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD); + if (!SD) + return; + + auto From = SD->getSpecializedTemplateOrPartial(); + if (auto *TD = From.dyn_cast<ClassTemplateDecl *>()) + checkTemplate(TD); + else if (auto *TD = + From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) { + if (!S.hasVisibleDeclaration(TD)) + diagnose(TD, true); + checkTemplate(TD); + } + } + + void checkInstantiated(VarDecl *RD) { + auto *SD = dyn_cast<VarTemplateSpecializationDecl>(RD); + if (!SD) + return; + + auto From = SD->getSpecializedTemplateOrPartial(); + if (auto *TD = From.dyn_cast<VarTemplateDecl *>()) + checkTemplate(TD); + else if (auto *TD = + From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) { + if (!S.hasVisibleDeclaration(TD)) + diagnose(TD, true); + checkTemplate(TD); + } + } + + void checkInstantiated(EnumDecl *FD) {} + + template<typename TemplDecl> + void checkTemplate(TemplDecl *TD) { + if (TD->isMemberSpecialization()) { + if (!S.hasVisibleMemberSpecialization(TD, &Modules)) + diagnose(TD->getMostRecentDecl(), false); + } + } +}; + +void Sema::checkSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec) { + if (!getLangOpts().Modules) + return; + + ExplicitSpecializationVisibilityChecker(*this, Loc).check(Spec); +} + +/// \brief Check whether a template partial specialization that we've discovered +/// is hidden, and produce suitable diagnostics if so. +void Sema::checkPartialSpecializationVisibility(SourceLocation Loc, + NamedDecl *Spec) { + llvm::SmallVector<Module *, 8> Modules; + if (!hasVisibleDeclaration(Spec, &Modules)) + diagnoseMissingImport(Loc, Spec, Spec->getLocation(), Modules, + MissingImportKind::PartialSpecialization, + /*Recover*/true); +} diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 42344e487ce..c9eaa243c6c 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1859,8 +1859,19 @@ static bool DiagnoseUninstantiableTemplate(Sema &S, TagDecl *PatternDef, TemplateSpecializationKind TSK, bool Complain = true) { - if (PatternDef && !PatternDef->isBeingDefined()) + if (PatternDef && !PatternDef->isBeingDefined()) { + NamedDecl *SuggestedDef = nullptr; + if (!S.hasVisibleDefinition(PatternDef, &SuggestedDef, + /*OnlyNeedComplete*/false)) { + // If we're allowed to diagnose this and recover, do so. + bool Recover = Complain && !S.isSFINAEContext(); + if (Complain) + S.diagnoseMissingImport(PointOfInstantiation, SuggestedDef, + Sema::MissingImportKind::Definition, Recover); + return !Recover; + } return false; + } if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) { // Say nothing @@ -2591,7 +2602,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, if (Enum->getDefinition()) continue; - EnumDecl *Pattern = Enum->getInstantiatedFromMemberEnum(); + EnumDecl *Pattern = Enum->getTemplateInstantiationPattern(); assert(Pattern && "Missing instantiated-from-template information"); if (TSK == TSK_ExplicitInstantiationDefinition) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 66b274f6260..ee4a0b3331f 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3585,6 +3585,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, Pattern = PatternDecl->getBody(PatternDecl); } + // FIXME: Check that the definition is visible before trying to instantiate + // it. This requires us to track the instantiation stack in order to know + // which definitions should be visible. + if (!Pattern && !PatternDecl->isDefaulted()) { if (DefinitionRequired) { if (Function->getPrimaryTemplate()) @@ -4078,6 +4082,10 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, Def = PatternDecl->getOutOfLineDefinition(); } + // FIXME: Check that the definition is visible before trying to instantiate + // it. This requires us to track the instantiation stack in order to know + // which definitions should be visible. + // If we don't have a definition of the variable template, we won't perform // any instantiation. Rather, we rely on the user to instantiate this // definition (or provide a specialization for it) in another translation diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 1ab43f909a8..c8c8af109b5 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -6799,8 +6799,8 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, RD = Pattern; D = RD->getDefinition(); } else if (auto *ED = dyn_cast<EnumDecl>(D)) { - while (auto *NewED = ED->getInstantiatedFromMemberEnum()) - ED = NewED; + if (auto *Pattern = ED->getTemplateInstantiationPattern()) + ED = Pattern; if (OnlyNeedComplete && ED->isFixed()) { // If the enum has a fixed underlying type, and we're only looking for a // complete type (not a definition), any visible declaration of it will @@ -6887,9 +6887,16 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, } } - // If we have a complete type, we're done. NamedDecl *Def = nullptr; - if (!T->isIncompleteType(&Def)) { + bool Incomplete = T->isIncompleteType(&Def); + + // Check that any necessary explicit specializations are visible. For an + // enum, we just need the declaration, so don't check this. + if (Def && !isa<EnumDecl>(Def)) + checkSpecializationVisibility(Loc, Def); + + // If we have a complete type, we're done. + if (!Incomplete) { // If we know about the definition but it is not visible, complain. NamedDecl *SuggestedDef = nullptr; if (Def && @@ -6898,7 +6905,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // definition visible. bool TreatAsComplete = Diagnoser && !isSFINAEContext(); if (Diagnoser) - diagnoseMissingImport(Loc, SuggestedDef, /*NeedDefinition*/true, + diagnoseMissingImport(Loc, SuggestedDef, MissingImportKind::Definition, /*Recover*/TreatAsComplete); return !TreatAsComplete; } @@ -6991,6 +6998,9 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, } } + // FIXME: If we didn't instantiate a definition because of an explicit + // specialization declaration, check that it's visible. + if (!Diagnoser) return true; |

