/// visible at the specified location.
void makeMergedDefinitionVisible(NamedDecl *ND);
- bool isModuleVisible(const Module *M) { return VisibleModules.isVisible(M); }
+ bool isModuleVisible(const Module *M, bool ModulePrivate = false);
/// Determine whether a declaration is visible to name lookup.
bool isVisible(const NamedDecl *D) {
bool CheckTemplateParameterList(TemplateParameterList *NewParams,
TemplateParameterList *OldParams,
- TemplateParamListContext TPC);
+ TemplateParamListContext TPC,
+ SkipBodyInfo *SkipBody = nullptr);
TemplateParameterList *MatchTemplateParametersToScopeSpecifier(
SourceLocation DeclStartLoc, SourceLocation DeclLoc,
const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId,
dumpName(D);
if (D->hasDefaultArgument())
dumpTemplateArgument(D->getDefaultArgument());
+ if (auto *From = D->getDefaultArgStorage().getInheritedFrom())
+ dumpDeclRef(From, D->defaultArgumentWasInherited() ? "inherited from"
+ : "previous");
}
void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
dumpName(D);
if (D->hasDefaultArgument())
dumpTemplateArgument(D->getDefaultArgument());
+ if (auto *From = D->getDefaultArgStorage().getInheritedFrom())
+ dumpDeclRef(From, D->defaultArgumentWasInherited() ? "inherited from"
+ : "previous");
}
void ASTDumper::VisitTemplateTemplateParmDecl(
dumpTemplateParameters(D->getTemplateParameters());
if (D->hasDefaultArgument())
dumpTemplateArgumentLoc(D->getDefaultArgument());
+ if (auto *From = D->getDefaultArgStorage().getInheritedFrom())
+ dumpDeclRef(From, D->defaultArgumentWasInherited() ? "inherited from"
+ : "previous");
}
void ASTDumper::VisitUsingDecl(const UsingDecl *D) {
Definition->getDescribedFunctionTemplate() ||
Definition->getNumTemplateParameterLists())) {
SkipBody->ShouldSkip = true;
+ SkipBody->Previous = const_cast<FunctionDecl*>(Definition);
if (auto *TD = Definition->getDescribedFunctionTemplate())
makeMergedDefinitionVisible(TD);
makeMergedDefinitionVisible(const_cast<FunctionDecl*>(Definition));
// many points during the parsing of a struct declaration (because
// the #pragma tokens are effectively skipped over during the
// parsing of the struct).
- if (TUK == TUK_Definition) {
+ if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip)) {
AddAlignmentAttributesForRecord(RD);
AddMsStructLayoutForRecord(RD);
}
// comparison.
SkipBody->CheckSameAsPrevious = true;
SkipBody->New = createTagFromNewDecl();
- SkipBody->Previous = Hidden;
+ SkipBody->Previous = Def;
+ return Def;
} else {
SkipBody->ShouldSkip = true;
+ SkipBody->Previous = Def;
makeMergedDefinitionVisible(Hidden);
+ // Carry on and handle it like a normal definition. We'll
+ // skip starting the definitiion later.
}
- return Def;
} else if (!IsExplicitSpecializationAfterInstantiation) {
// A redeclaration in function prototype scope in C isn't
// visible elsewhere, so merely issue a warning.
// many points during the parsing of a struct declaration (because
// the #pragma tokens are effectively skipped over during the
// parsing of the struct).
- if (TUK == TUK_Definition) {
+ if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip)) {
AddAlignmentAttributesForRecord(RD);
AddMsStructLayoutForRecord(RD);
}
if (PrevDecl)
CheckRedeclarationModuleOwnership(New, PrevDecl);
- if (TUK == TUK_Definition)
+ if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip))
New->startDefinition();
ProcessDeclAttributeList(S, New, Attrs);
if (auto RD = dyn_cast<RecordDecl>(New))
RD->completeDefinition();
return nullptr;
+ } else if (SkipBody && SkipBody->ShouldSkip) {
+ return SkipBody->Previous;
} else {
return New;
}
OldDecl->getTemplateParameters(),
/*Complain=*/true,
TPL_TemplateMatch))
- OldTemplateParams = OldDecl->getTemplateParameters();
+ OldTemplateParams =
+ OldDecl->getMostRecentDecl()->getTemplateParameters();
else
Invalid = true;
return LookupModulesCache;
}
+/// Determine whether the module M is part of the current module from the
+/// perspective of a module-private visibility check.
+static bool isInCurrentModule(const Module *M, const LangOptions &LangOpts) {
+ // If M is the global module fragment of a module that we've not yet finished
+ // parsing, then it must be part of the current module.
+ return M->getTopLevelModuleName() == LangOpts.CurrentModule ||
+ (M->Kind == Module::GlobalModuleFragment && !M->Parent);
+}
+
bool Sema::hasVisibleMergedDefinition(NamedDecl *Def) {
- for (Module *Merged : Context.getModulesWithMergedDefinition(Def))
+ for (const Module *Merged : Context.getModulesWithMergedDefinition(Def))
if (isModuleVisible(Merged))
return true;
return false;
if (Def->getModuleOwnershipKind() == Decl::ModuleOwnershipKind::Visible &&
getLangOpts().ModulesLocalVisibility)
return true;
- for (Module *Merged : Context.getModulesWithMergedDefinition(Def))
- if (Merged->getTopLevelModuleName() == getLangOpts().CurrentModule)
+ for (const Module *Merged : Context.getModulesWithMergedDefinition(Def))
+ if (isInCurrentModule(Merged, getLangOpts()))
return true;
return false;
}
if (!DefaultArg.isInherited() && Modules) {
auto *NonConstD = const_cast<ParmDecl*>(D);
Modules->push_back(S.getOwningModule(NonConstD));
- const auto &Merged = S.Context.getModulesWithMergedDefinition(NonConstD);
- Modules->insert(Modules->end(), Merged.begin(), Merged.end());
}
// If there was a previous default argument, maybe its parameter is visible.
HasFilteredRedecls = true;
- if (Modules) {
+ if (Modules)
Modules->push_back(R->getOwningModule());
- const auto &Merged = S.Context.getModulesWithMergedDefinition(R);
- Modules->insert(Modules->end(), Merged.begin(), Merged.end());
- }
}
// Only return false if there is at least one redecl that is not filtered out.
assert(D->isHidden() && "should not call this: not in slow case");
Module *DeclModule = SemaRef.getOwningModule(D);
- if (!DeclModule) {
- // A module-private declaration with no owning module means this is in the
- // global module in the C++ Modules TS. This is visible within the same
- // translation unit only.
- // FIXME: Don't assume that "same translation unit" means the same thing
- // as "not from an AST file".
- assert(D->isModulePrivate() && "hidden decl has no module");
- if (!D->isFromASTFile() || SemaRef.hasMergedDefinitionInCurrentModule(D))
- return true;
- } else {
- // If the owning module is visible, and the decl is not module private,
- // then the decl is visible too. (Module private is ignored within the same
- // top-level module.)
- if (D->isModulePrivate()
- ? DeclModule->getTopLevelModuleName() ==
- SemaRef.getLangOpts().CurrentModule ||
- SemaRef.hasMergedDefinitionInCurrentModule(D)
- : SemaRef.isModuleVisible(DeclModule) ||
- SemaRef.hasVisibleMergedDefinition(D))
- return true;
- }
+ assert(DeclModule && "hidden decl has no owning module");
+
+ // If the owning module is visible, the decl is visible.
+ if (SemaRef.isModuleVisible(DeclModule, D->isModulePrivate()))
+ return true;
// Determine whether a decl context is a file context for the purpose of
// visibility. This looks through some (export and linkage spec) transparent
return VisibleWithinParent;
}
- // FIXME: All uses of DeclModule below this point should also check merged
- // modules.
- if (!DeclModule)
- return false;
+ return false;
+}
+
+bool Sema::isModuleVisible(const Module *M, bool ModulePrivate) {
+ // The module might be ordinarily visible. For a module-private query, that
+ // means it is part of the current module. For any other query, that means it
+ // is in our visible module set.
+ if (ModulePrivate) {
+ if (isInCurrentModule(M, getLangOpts()))
+ return true;
+ } else {
+ if (VisibleModules.isVisible(M))
+ return true;
+ }
+
+ // Otherwise, it might be visible by virtue of the query being within a
+ // template instantiation or similar that is permitted to look inside M.
// Find the extra places where we need to look.
- const auto &LookupModules = SemaRef.getLookupModules();
+ const auto &LookupModules = getLookupModules();
if (LookupModules.empty())
return false;
- // If our lookup set contains the decl's module, it's visible.
- if (LookupModules.count(DeclModule))
+ // If our lookup set contains the module, it's visible.
+ if (LookupModules.count(M))
return true;
- // If the declaration isn't exported, it's not visible in any other module.
- if (D->isModulePrivate())
+ // For a module-private query, that's everywhere we get to look.
+ if (ModulePrivate)
return false;
- // Check whether DeclModule is transitively exported to an import of
- // the lookup set.
+ // Check whether M is transitively exported to an import of the lookup set.
return std::any_of(LookupModules.begin(), LookupModules.end(),
- [&](const Module *M) {
- return M->isModuleVisible(DeclModule); });
+ [&](const Module *LookupM) {
+ return LookupM->isModuleVisible(M); });
}
bool Sema::isVisibleSlow(const NamedDecl *D) {
if (!Def)
Def = Decl;
- Module *Owner = getOwningModule(Decl);
+ Module *Owner = getOwningModule(Def);
assert(Owner && "definition of hidden declaration is not in a module");
llvm::SmallVector<Module*, 8> OwningModules;
OwningModules.push_back(Owner);
- auto Merged = Context.getModulesWithMergedDefinition(Decl);
+ auto Merged = Context.getModulesWithMergedDefinition(Def);
OwningModules.insert(OwningModules.end(), Merged.begin(), Merged.end());
diagnoseMissingImport(Loc, Decl, Decl->getLocation(), OwningModules, MIK,
NamedDecl *Hidden = nullptr;
if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
SkipBody->ShouldSkip = true;
+ SkipBody->Previous = Def;
auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
assert(Tmpl && "original definition of a class template is not a "
"class template?");
makeMergedDefinitionVisible(Hidden);
makeMergedDefinitionVisible(Tmpl);
- return Def;
+ } else {
+ Diag(NameLoc, diag::err_redefinition) << Name;
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ // FIXME: Would it make sense to try to "forget" the previous
+ // definition, as part of error recovery?
+ return true;
}
-
- Diag(NameLoc, diag::err_redefinition) << Name;
- Diag(Def->getLocation(), diag::note_previous_definition);
- // FIXME: Would it make sense to try to "forget" the previous
- // definition, as part of error recovery?
- return true;
}
}
} else if (PrevDecl) {
if (!(TUK == TUK_Friend && CurContext->isDependentContext()) &&
CheckTemplateParameterList(
TemplateParams,
- PrevClassTemplate ? PrevClassTemplate->getTemplateParameters()
- : nullptr,
+ PrevClassTemplate
+ ? PrevClassTemplate->getMostRecentDecl()->getTemplateParameters()
+ : nullptr,
(SS.isSet() && SemanticContext && SemanticContext->isRecord() &&
SemanticContext->isDependentContext())
? TPC_ClassTemplateMember
- : TUK == TUK_Friend ? TPC_FriendClassTemplate
- : TPC_ClassTemplate))
+ : TUK == TUK_Friend ? TPC_FriendClassTemplate : TPC_ClassTemplate,
+ SkipBody))
Invalid = true;
if (SS.isSet()) {
// Add alignment attributes if necessary; these attributes are checked when
// the ASTContext lays out the structure.
- if (TUK == TUK_Definition) {
+ if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip)) {
AddAlignmentAttributesForRecord(NewClass);
AddMsStructLayoutForRecord(NewClass);
}
NewClass->setLexicalDeclContext(CurContext);
NewTemplate->setLexicalDeclContext(CurContext);
- if (TUK == TUK_Definition)
+ if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip))
NewClass->startDefinition();
ProcessDeclAttributeList(S, NewClass, Attr);
ActOnDocumentableDecl(NewTemplate);
+ if (SkipBody && SkipBody->ShouldSkip)
+ return SkipBody->Previous;
+
return NewTemplate;
}
/// \param TPC Describes the context in which we are checking the given
/// template parameter list.
///
+/// \param SkipBody If we might have already made a prior merged definition
+/// of this template visible, the corresponding body-skipping information.
+/// Default argument redefinition is not an error when skipping such a body,
+/// because (under the ODR) we can assume the default arguments are the same
+/// as the prior merged definition.
+///
/// \returns true if an error occurred, false otherwise.
bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
TemplateParameterList *OldParams,
- TemplateParamListContext TPC) {
+ TemplateParamListContext TPC,
+ SkipBodyInfo *SkipBody) {
bool Invalid = false;
// C++ [temp.param]p10:
"Parameter packs can't have a default argument!");
SawParameterPack = true;
} else if (OldTypeParm && hasVisibleDefaultArgument(OldTypeParm) &&
- NewTypeParm->hasDefaultArgument()) {
+ NewTypeParm->hasDefaultArgument() &&
+ (!SkipBody || !SkipBody->ShouldSkip)) {
OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc();
SawDefaultArgument = true;
if (!NewNonTypeParm->isPackExpansion())
SawParameterPack = true;
} else if (OldNonTypeParm && hasVisibleDefaultArgument(OldNonTypeParm) &&
- NewNonTypeParm->hasDefaultArgument()) {
+ NewNonTypeParm->hasDefaultArgument() &&
+ (!SkipBody || !SkipBody->ShouldSkip)) {
OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc();
SawDefaultArgument = true;
SawParameterPack = true;
} else if (OldTemplateParm &&
hasVisibleDefaultArgument(OldTemplateParm) &&
- NewTemplateParm->hasDefaultArgument()) {
+ NewTemplateParm->hasDefaultArgument() &&
+ (!SkipBody || !SkipBody->ShouldSkip)) {
OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation();
NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation();
SawDefaultArgument = true;
NamedDecl *Hidden = nullptr;
if (Def && SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
SkipBody->ShouldSkip = true;
+ SkipBody->Previous = Def;
makeMergedDefinitionVisible(Hidden);
- // From here on out, treat this as just a redeclaration.
- TUK = TUK_Declaration;
} else if (Def) {
SourceRange Range(TemplateNameLoc, RAngleLoc);
Diag(TemplateNameLoc, diag::err_redefinition) << Specialization << Range;
// Add alignment attributes if necessary; these attributes are checked when
// the ASTContext lays out the structure.
- if (TUK == TUK_Definition) {
+ if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip)) {
AddAlignmentAttributesForRecord(Specialization);
AddMsStructLayoutForRecord(Specialization);
}
Specialization->setLexicalDeclContext(CurContext);
// We may be starting the definition of this specialization.
- if (TUK == TUK_Definition)
+ if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip))
Specialization->startDefinition();
if (TUK == TUK_Friend) {
// context. However, specializations are not found by name lookup.
CurContext->addDecl(Specialization);
}
+
+ if (SkipBody && SkipBody->ShouldSkip)
+ return SkipBody->Previous;
+
return Specialization;
}
}
TemplateParameterList *PrevParams
- = PrevClassTemplate->getTemplateParameters();
+ = PrevClassTemplate->getMostRecentDecl()->getTemplateParameters();
// Make sure the parameter lists match.
if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams,
assert(D && "missing definition for pattern of instantiated definition");
*Suggested = D;
- if (isVisible(D))
+
+ auto DefinitionIsVisible = [&] {
+ // The (primary) definition might be in a visible module.
+ if (isVisible(D))
+ return true;
+
+ // A visible module might have a merged definition instead.
+ if (D->isModulePrivate() ? hasMergedDefinitionInCurrentModule(D)
+ : hasVisibleMergedDefinition(D))
+ return true;
+
+ return false;
+ };
+
+ if (DefinitionIsVisible())
return true;
// The external source may have additional definitions of this entity that are
// visible, so complete the redeclaration chain now and ask again.
if (auto *Source = Context.getExternalSource()) {
Source->CompleteRedeclChain(D);
- return isVisible(D);
+ return DefinitionIsVisible();
}
return false;
J<> pre_j; // expected-error {{declaration of 'J' must be imported}}
#ifdef IMPORT_USE_2
-// expected-error-re@-2 {{default argument of 'J' must be imported from one of {{.*}}stuff.use{{.*}}stuff.use-2}}
+// expected-error-re@-2 {{default argument of 'J' must be imported from one of {{.*}}stuff.use-2{{.*}}stuff.use}}
#elif EARLY_INDIRECT_INCLUDE
// expected-error@-4 {{default argument of 'J' must be imported from module 'merged-defs'}}
#else