summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaTemplate.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2018-09-12 02:13:47 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2018-09-12 02:13:47 +0000
commitc457766c6d739ba717f881b36a76ff60d3b75809 (patch)
tree294731666a45d2531fbf35de0720e1585d01ccde /clang/lib/Sema/SemaTemplate.cpp
parent20fbdb347cf6324e6e8d3f4aa1d0b1ab02f70e8d (diff)
downloadbcm5719-llvm-c457766c6d739ba717f881b36a76ff60d3b75809.tar.gz
bcm5719-llvm-c457766c6d739ba717f881b36a76ff60d3b75809.zip
Consistently create a new declaration when merging a pre-existing but
hidden definition with a would-be-parsed redefinition. This permits a bunch of cleanups. In particular, we no longer need to take merged definitions into account when checking declaration visibility, only when checking definition visibility, which makes certain visibility checks take linear instead of quadratic time. We could also now remove the UPD_DECL_EXPORTED update record and track on each declaration whether it was demoted from a definition (as we already do for variables), but I'm not doing that in this patch to keep the changes here simpler. llvm-svn: 342018
Diffstat (limited to 'clang/lib/Sema/SemaTemplate.cpp')
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp59
1 files changed, 38 insertions, 21 deletions
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index c826b836a70..61e51de349e 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1487,19 +1487,19 @@ DeclResult Sema::CheckClassTemplate(
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) {
@@ -1520,13 +1520,14 @@ DeclResult Sema::CheckClassTemplate(
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()) {
@@ -1561,7 +1562,7 @@ DeclResult Sema::CheckClassTemplate(
// 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);
}
@@ -1604,7 +1605,7 @@ DeclResult Sema::CheckClassTemplate(
NewClass->setLexicalDeclContext(CurContext);
NewTemplate->setLexicalDeclContext(CurContext);
- if (TUK == TUK_Definition)
+ if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip))
NewClass->startDefinition();
ProcessDeclAttributeList(S, NewClass, Attr);
@@ -1653,6 +1654,9 @@ DeclResult Sema::CheckClassTemplate(
ActOnDocumentableDecl(NewTemplate);
+ if (SkipBody && SkipBody->ShouldSkip)
+ return SkipBody->Previous;
+
return NewTemplate;
}
@@ -2150,10 +2154,17 @@ static bool DiagnoseUnexpandedParameterPacks(Sema &S,
/// \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:
@@ -2203,7 +2214,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
"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;
@@ -2247,7 +2259,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
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;
@@ -2290,7 +2303,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
SawParameterPack = true;
} else if (OldTemplateParm &&
hasVisibleDefaultArgument(OldTemplateParm) &&
- NewTemplateParm->hasDefaultArgument()) {
+ NewTemplateParm->hasDefaultArgument() &&
+ (!SkipBody || !SkipBody->ShouldSkip)) {
OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation();
NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation();
SawDefaultArgument = true;
@@ -7689,9 +7703,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
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;
@@ -7705,7 +7718,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// 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);
}
@@ -7741,7 +7754,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
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) {
@@ -7757,6 +7770,10 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// context. However, specializations are not found by name lookup.
CurContext->addDecl(Specialization);
}
+
+ if (SkipBody && SkipBody->ShouldSkip)
+ return SkipBody->Previous;
+
return Specialization;
}
OpenPOWER on IntegriCloud