Skip to content

Commit f9f50a2

Browse files
committed
[FOLD] unify template/non-template declaration parsing
1 parent 357d466 commit f9f50a2

File tree

5 files changed

+176
-212
lines changed

5 files changed

+176
-212
lines changed

clang/include/clang/Parse/Parser.h

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2419,6 +2419,7 @@ class Parser : public CodeCompletionHandler {
24192419
bool MightBeDeclarator(DeclaratorContext Context);
24202420
DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context,
24212421
ParsedAttributes &Attrs,
2422+
ParsedTemplateInfo &TemplateInfo,
24222423
SourceLocation *DeclEnd = nullptr,
24232424
ForRangeInit *FRI = nullptr);
24242425
Decl *ParseDeclarationAfterDeclarator(Declarator &D,
@@ -3590,16 +3591,15 @@ class Parser : public CodeCompletionHandler {
35903591
// C++ 14: Templates [temp]
35913592

35923593
// C++ 14.1: Template Parameters [temp.param]
3593-
Decl *ParseDeclarationStartingWithTemplate(DeclaratorContext Context,
3594-
SourceLocation &DeclEnd,
3595-
ParsedAttributes &AccessAttrs,
3596-
AccessSpecifier AS = AS_none);
3597-
Decl *ParseTemplateDeclarationOrSpecialization(DeclaratorContext Context,
3598-
SourceLocation &DeclEnd,
3599-
ParsedAttributes &AccessAttrs,
3600-
AccessSpecifier AS);
3601-
Decl *ParseSingleDeclarationAfterTemplate(
3602-
DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo,
3594+
DeclGroupPtrTy
3595+
ParseDeclarationStartingWithTemplate(DeclaratorContext Context,
3596+
SourceLocation &DeclEnd,
3597+
ParsedAttributes &AccessAttrs);
3598+
DeclGroupPtrTy ParseTemplateDeclarationOrSpecialization(
3599+
DeclaratorContext Context, SourceLocation &DeclEnd,
3600+
ParsedAttributes &AccessAttrs, AccessSpecifier AS);
3601+
DeclGroupPtrTy ParseDeclarationAfterTemplate(
3602+
DeclaratorContext Context, ParsedTemplateInfo &TemplateInfo,
36033603
ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd,
36043604
ParsedAttributes &AccessAttrs, AccessSpecifier AS = AS_none);
36053605
bool ParseTemplateParameters(MultiParseScope &TemplateScopes, unsigned Depth,
@@ -3648,12 +3648,12 @@ class Parser : public CodeCompletionHandler {
36483648
TemplateTy Template, SourceLocation OpenLoc);
36493649
ParsedTemplateArgument ParseTemplateTemplateArgument();
36503650
ParsedTemplateArgument ParseTemplateArgument();
3651-
Decl *ParseExplicitInstantiation(DeclaratorContext Context,
3652-
SourceLocation ExternLoc,
3653-
SourceLocation TemplateLoc,
3654-
SourceLocation &DeclEnd,
3655-
ParsedAttributes &AccessAttrs,
3656-
AccessSpecifier AS = AS_none);
3651+
DeclGroupPtrTy ParseExplicitInstantiation(DeclaratorContext Context,
3652+
SourceLocation ExternLoc,
3653+
SourceLocation TemplateLoc,
3654+
SourceLocation &DeclEnd,
3655+
ParsedAttributes &AccessAttrs,
3656+
AccessSpecifier AS = AS_none);
36573657
// C++2a: Template, concept definition [temp]
36583658
Decl *
36593659
ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,

clang/lib/Parse/ParseDecl.cpp

Lines changed: 84 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,9 +1916,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
19161916
case tok::kw_export:
19171917
ProhibitAttributes(DeclAttrs);
19181918
ProhibitAttributes(DeclSpecAttrs);
1919-
SingleDecl =
1920-
ParseDeclarationStartingWithTemplate(Context, DeclEnd, DeclAttrs);
1921-
break;
1919+
return ParseDeclarationStartingWithTemplate(Context, DeclEnd, DeclAttrs);
19221920
case tok::kw_inline:
19231921
// Could be the start of an inline namespace. Allowed as an ext in C++03.
19241922
if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) {
@@ -1994,8 +1992,9 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
19941992
ParsingDeclSpec DS(*this);
19951993
DS.takeAttributesFrom(DeclSpecAttrs);
19961994

1995+
ParsedTemplateInfo TemplateInfo;
19971996
DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(Context);
1998-
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, DSContext);
1997+
ParseDeclarationSpecifiers(DS, TemplateInfo, AS_none, DSContext);
19991998

20001999
// If we had a free-standing type definition with a missing semicolon, we
20012000
// may get this far before the problem becomes obvious.
@@ -2027,7 +2026,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
20272026
if (DeclSpecStart)
20282027
DS.SetRangeStart(*DeclSpecStart);
20292028

2030-
return ParseDeclGroup(DS, Context, DeclAttrs, &DeclEnd, FRI);
2029+
return ParseDeclGroup(DS, Context, DeclAttrs, TemplateInfo, &DeclEnd, FRI);
20312030
}
20322031

20332032
/// Returns true if this might be the start of a declarator, or a common typo
@@ -2184,6 +2183,7 @@ void Parser::SkipMalformedDecl() {
21842183
Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
21852184
DeclaratorContext Context,
21862185
ParsedAttributes &Attrs,
2186+
ParsedTemplateInfo &TemplateInfo,
21872187
SourceLocation *DeclEnd,
21882188
ForRangeInit *FRI) {
21892189
// Parse the first declarator.
@@ -2193,8 +2193,19 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
21932193
ParsedAttributes LocalAttrs(AttrFactory);
21942194
LocalAttrs.takeAllFrom(Attrs);
21952195
ParsingDeclarator D(*this, DS, LocalAttrs, Context);
2196+
if (TemplateInfo.TemplateParams)
2197+
D.setTemplateParameterLists(*TemplateInfo.TemplateParams);
2198+
2199+
bool IsTemplateSpecOrInst =
2200+
(TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
2201+
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
2202+
SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst);
2203+
21962204
ParseDeclarator(D);
21972205

2206+
if (IsTemplateSpecOrInst)
2207+
SAC.done();
2208+
21982209
// Bail out if the first declarator didn't seem well-formed.
21992210
if (!D.hasName() && !D.mayOmitIdentifier()) {
22002211
SkipMalformedDecl();
@@ -2262,15 +2273,54 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
22622273
// need to handle the file scope definition case.
22632274
if (Context == DeclaratorContext::File) {
22642275
if (isStartOfFunctionDefinition(D)) {
2276+
// C++23 [dcl.typedef] p1:
2277+
// The typedef specifier shall not be [...], and it shall not be
2278+
// used in the decl-specifier-seq of a parameter-declaration nor in
2279+
// the decl-specifier-seq of a function-definition.
22652280
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
2266-
Diag(Tok, diag::err_function_declared_typedef);
2267-
2268-
// Recover by treating the 'typedef' as spurious.
2281+
// If the user intended to write 'typename', we should have already
2282+
// suggested adding it elsewhere. In any case, recover by ignoring
2283+
// 'typedef' and suggest removing it.
2284+
Diag(DS.getStorageClassSpecLoc(),
2285+
diag::err_function_declared_typedef)
2286+
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
22692287
DS.ClearStorageClassSpecs();
22702288
}
2289+
Decl *TheDecl = nullptr;
2290+
2291+
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
2292+
if (D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) {
2293+
// If the declarator-id is not a template-id, issue a diagnostic
2294+
// and recover by ignoring the 'template' keyword.
2295+
Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0;
2296+
TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(),
2297+
&LateParsedAttrs);
2298+
} else {
2299+
SourceLocation LAngleLoc =
2300+
PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
2301+
Diag(D.getIdentifierLoc(),
2302+
diag::err_explicit_instantiation_with_definition)
2303+
<< SourceRange(TemplateInfo.TemplateLoc)
2304+
<< FixItHint::CreateInsertion(LAngleLoc, "<>");
2305+
2306+
// Recover as if it were an explicit specialization.
2307+
TemplateParameterLists FakedParamLists;
2308+
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
2309+
0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc,
2310+
std::nullopt, LAngleLoc, nullptr));
2311+
2312+
TheDecl = ParseFunctionDefinition(
2313+
D,
2314+
ParsedTemplateInfo(&FakedParamLists,
2315+
/*isSpecialization=*/true,
2316+
/*lastParameterListWasEmpty=*/true),
2317+
&LateParsedAttrs);
2318+
}
2319+
} else {
2320+
TheDecl =
2321+
ParseFunctionDefinition(D, TemplateInfo, &LateParsedAttrs);
2322+
}
22712323

2272-
Decl *TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(),
2273-
&LateParsedAttrs);
22742324
return Actions.ConvertDeclToDeclGroup(TheDecl);
22752325
}
22762326

@@ -2334,8 +2384,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
23342384
}
23352385

23362386
SmallVector<Decl *, 8> DeclsInGroup;
2337-
Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(
2338-
D, ParsedTemplateInfo(), FRI);
2387+
Decl *FirstDecl =
2388+
ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo, FRI);
23392389
if (LateParsedAttrs.size() > 0)
23402390
ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false);
23412391
D.complete(FirstDecl);
@@ -2358,6 +2408,16 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
23582408
break;
23592409
}
23602410

2411+
// C++23 [temp.pre]p5:
2412+
// In a template-declaration, explicit specialization, or explicit
2413+
// instantiation the init-declarator-list in the declaration shall
2414+
// contain at most one declarator.
2415+
if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
2416+
D.isFirstDeclarator()) {
2417+
Diag(CommaLoc, diag::err_multiple_template_declarators)
2418+
<< TemplateInfo.Kind;
2419+
}
2420+
23612421
// Parse the next declarator.
23622422
D.clear();
23632423
D.setCommaLoc(CommaLoc);
@@ -2387,7 +2447,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
23872447
// declarator requires-clause
23882448
if (Tok.is(tok::kw_requires))
23892449
ParseTrailingRequiresClause(D);
2390-
Decl *ThisDecl = ParseDeclarationAfterDeclarator(D);
2450+
Decl *ThisDecl = ParseDeclarationAfterDeclarator(D, TemplateInfo);
23912451
D.complete(ThisDecl);
23922452
if (ThisDecl)
23932453
DeclsInGroup.push_back(ThisDecl);
@@ -6495,6 +6555,17 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
64956555
/*ObjectHasErrors=*/false, EnteringContext);
64966556
}
64976557

6558+
// C++23 [basic.scope.namespace]p1:
6559+
// For each non-friend redeclaration or specialization whose target scope
6560+
// is or is contained by the scope, the portion after the declarator-id,
6561+
// class-head-name, or enum-head-name is also included in the scope.
6562+
// C++23 [basic.scope.class]p1:
6563+
// For each non-friend redeclaration or specialization whose target scope
6564+
// is or is contained by the scope, the portion after the declarator-id,
6565+
// class-head-name, or enum-head-name is also included in the scope.
6566+
//
6567+
// FIXME: We should not be doing this for friend declarations; they have
6568+
// their own special lookup semantics specified by [basic.lookup.unqual]p6.
64986569
if (D.getCXXScopeSpec().isValid()) {
64996570
if (Actions.ShouldEnterDeclaratorScope(getCurScope(),
65006571
D.getCXXScopeSpec()))

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2760,7 +2760,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
27602760
}
27612761

27622762
// static_assert-declaration. A templated static_assert declaration is
2763-
// diagnosed in Parser::ParseSingleDeclarationAfterTemplate.
2763+
// diagnosed in Parser::ParseDeclarationAfterTemplate.
27642764
if (!TemplateInfo.Kind &&
27652765
Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
27662766
SourceLocation DeclEnd;
@@ -2773,9 +2773,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
27732773
"Nested template improperly parsed?");
27742774
ObjCDeclContextSwitch ObjCDC(*this);
27752775
SourceLocation DeclEnd;
2776-
return DeclGroupPtrTy::make(
2777-
DeclGroupRef(ParseTemplateDeclarationOrSpecialization(
2778-
DeclaratorContext::Member, DeclEnd, AccessAttrs, AS)));
2776+
return ParseTemplateDeclarationOrSpecialization(DeclaratorContext::Member,
2777+
DeclEnd, AccessAttrs, AS);
27792778
}
27802779

27812780
// Handle: member-declaration ::= '__extension__' member-declaration
@@ -3167,15 +3166,6 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
31673166

31683167
DeclaratorInfo.complete(ThisDecl);
31693168

3170-
if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) {
3171-
if (Tok.is(tok::comma)) {
3172-
Diag(Tok, diag::err_multiple_template_declarators)
3173-
<< (int)TemplateInfo.Kind;
3174-
SkipUntil(tok::semi, StopBeforeMatch);
3175-
}
3176-
break;
3177-
}
3178-
31793169
// If we don't have a comma, it is either the end of the list (a ';')
31803170
// or an error, bail out.
31813171
SourceLocation CommaLoc;
@@ -3193,6 +3183,16 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
31933183
break;
31943184
}
31953185

3186+
// C++23 [temp.pre]p5:
3187+
// In a template-declaration, explicit specialization, or explicit
3188+
// instantiation the init-declarator-list in the declaration shall
3189+
// contain at most one declarator.
3190+
if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
3191+
DeclaratorInfo.isFirstDeclarator()) {
3192+
Diag(CommaLoc, diag::err_multiple_template_declarators)
3193+
<< TemplateInfo.Kind;
3194+
}
3195+
31963196
// Parse the next declarator.
31973197
DeclaratorInfo.clear();
31983198
VS.clear();
@@ -4138,6 +4138,24 @@ void Parser::ParseTrailingRequiresClause(Declarator &D) {
41384138

41394139
SourceLocation RequiresKWLoc = ConsumeToken();
41404140

4141+
// C++23 [basic.scope.namespace]p1:
4142+
// For each non-friend redeclaration or specialization whose target scope
4143+
// is or is contained by the scope, the portion after the declarator-id,
4144+
// class-head-name, or enum-head-name is also included in the scope.
4145+
// C++23 [basic.scope.class]p1:
4146+
// For each non-friend redeclaration or specialization whose target scope
4147+
// is or is contained by the scope, the portion after the declarator-id,
4148+
// class-head-name, or enum-head-name is also included in the scope.
4149+
//
4150+
// FIXME: We should really be calling ParseTrailingRequiresClause in
4151+
// ParseDirectDeclarator, when we are already in the declarator scope.
4152+
// This would also correctly suppress access checks for specializations
4153+
// and explicit instantiations, which we currently do not do.
4154+
CXXScopeSpec &SS = D.getCXXScopeSpec();
4155+
DeclaratorScopeObj DeclScopeObj(*this, SS);
4156+
if (SS.isValid() && Actions.ShouldEnterDeclaratorScope(getCurScope(), SS))
4157+
DeclScopeObj.EnterDeclaratorScope();
4158+
41414159
ExprResult TrailingRequiresClause;
41424160
ParseScope ParamScope(this, Scope::DeclScope |
41434161
Scope::FunctionDeclarationScope |

0 commit comments

Comments
 (0)