Skip to content

Commit 27ec7b3

Browse files
committed
[WIP] parse multiple declarators in template-declarations
1 parent 2bb667e commit 27ec7b3

File tree

5 files changed

+90
-140
lines changed

5 files changed

+90
-140
lines changed

clang/include/clang/Parse/Parser.h

Lines changed: 2 additions & 1 deletion
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,
@@ -3599,7 +3600,7 @@ class Parser : public CodeCompletionHandler {
35993600
ParsedAttributes &AccessAttrs,
36003601
AccessSpecifier AS);
36013602
Decl *ParseSingleDeclarationAfterTemplate(
3602-
DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo,
3603+
DeclaratorContext Context, ParsedTemplateInfo &TemplateInfo,
36033604
ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd,
36043605
ParsedAttributes &AccessAttrs, AccessSpecifier AS = AS_none);
36053606
bool ParseTemplateParameters(MultiParseScope &TemplateScopes, unsigned Depth,

clang/lib/Parse/ParseDecl.cpp

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2027,7 +2027,8 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
20272027
if (DeclSpecStart)
20282028
DS.SetRangeStart(*DeclSpecStart);
20292029

2030-
return ParseDeclGroup(DS, Context, DeclAttrs, &DeclEnd, FRI);
2030+
ParsedTemplateInfo TemplateInfo;
2031+
return ParseDeclGroup(DS, Context, DeclAttrs, TemplateInfo, &DeclEnd, FRI);
20312032
}
20322033

20332034
/// Returns true if this might be the start of a declarator, or a common typo
@@ -2184,6 +2185,7 @@ void Parser::SkipMalformedDecl() {
21842185
Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
21852186
DeclaratorContext Context,
21862187
ParsedAttributes &Attrs,
2188+
ParsedTemplateInfo &TemplateInfo,
21872189
SourceLocation *DeclEnd,
21882190
ForRangeInit *FRI) {
21892191
// Parse the first declarator.
@@ -2193,8 +2195,29 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
21932195
ParsedAttributes LocalAttrs(AttrFactory);
21942196
LocalAttrs.takeAllFrom(Attrs);
21952197
ParsingDeclarator D(*this, DS, LocalAttrs, Context);
2198+
if (TemplateInfo.TemplateParams)
2199+
D.setTemplateParameterLists(*TemplateInfo.TemplateParams);
2200+
2201+
// Turn off usual access checking for template specializations and
2202+
// instantiations.
2203+
// C++20 [temp.spec] 13.9/6.
2204+
// This disables the access checking rules for function template explicit
2205+
// instantiation and explicit specialization:
2206+
// - parameter-list;
2207+
// - template-argument-list;
2208+
// - noexcept-specifier;
2209+
// - dynamic-exception-specifications (deprecated in C++11, removed since
2210+
// C++17).
2211+
bool IsTemplateSpecOrInst =
2212+
(TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
2213+
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
2214+
SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst);
2215+
21962216
ParseDeclarator(D);
21972217

2218+
if (IsTemplateSpecOrInst)
2219+
SAC.done();
2220+
21982221
// Bail out if the first declarator didn't seem well-formed.
21992222
if (!D.hasName() && !D.mayOmitIdentifier()) {
22002223
SkipMalformedDecl();
@@ -2204,8 +2227,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
22042227
if (getLangOpts().HLSL)
22052228
MaybeParseHLSLSemantics(D);
22062229

2207-
if (Tok.is(tok::kw_requires))
2230+
if (Tok.is(tok::kw_requires)) {
2231+
CXXScopeSpec &ScopeSpec = D.getCXXScopeSpec();
2232+
DeclaratorScopeObj DeclScopeObj(*this, ScopeSpec);
2233+
if (ScopeSpec.isValid() &&
2234+
Actions.ShouldEnterDeclaratorScope(getCurScope(), ScopeSpec))
2235+
DeclScopeObj.EnterDeclaratorScope();
22082236
ParseTrailingRequiresClause(D);
2237+
}
22092238

22102239
// Save late-parsed attributes for now; they need to be parsed in the
22112240
// appropriate function scope after the function Decl has been constructed.
@@ -2269,8 +2298,34 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
22692298
DS.ClearStorageClassSpecs();
22702299
}
22712300

2272-
Decl *TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(),
2273-
&LateParsedAttrs);
2301+
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
2302+
if (D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) {
2303+
// If the declarator-id is not a template-id, issue a diagnostic
2304+
// and recover by ignoring the 'template' keyword.
2305+
Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0;
2306+
TemplateInfo = ParsedTemplateInfo();
2307+
} else {
2308+
SourceLocation LAngleLoc =
2309+
PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
2310+
Diag(D.getIdentifierLoc(),
2311+
diag::err_explicit_instantiation_with_definition)
2312+
<< SourceRange(TemplateInfo.TemplateLoc)
2313+
<< FixItHint::CreateInsertion(LAngleLoc, "<>");
2314+
2315+
// Recover as if it were an explicit specialization.
2316+
TemplateParameterLists FakedParamLists;
2317+
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
2318+
0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc,
2319+
std::nullopt, LAngleLoc, nullptr));
2320+
TemplateInfo =
2321+
ParsedTemplateInfo(&FakedParamLists,
2322+
/*isSpecialization=*/true,
2323+
/*lastParameterListWasEmpty=*/true);
2324+
}
2325+
}
2326+
2327+
Decl *TheDecl =
2328+
ParseFunctionDefinition(D, TemplateInfo, &LateParsedAttrs);
22742329
return Actions.ConvertDeclToDeclGroup(TheDecl);
22752330
}
22762331

@@ -2334,8 +2389,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
23342389
}
23352390

23362391
SmallVector<Decl *, 8> DeclsInGroup;
2337-
Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(
2338-
D, ParsedTemplateInfo(), FRI);
2392+
Decl *FirstDecl =
2393+
ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo, FRI);
23392394
if (LateParsedAttrs.size() > 0)
23402395
ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false);
23412396
D.complete(FirstDecl);
@@ -2344,6 +2399,13 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
23442399

23452400
bool ExpectSemi = Context != DeclaratorContext::ForInit;
23462401

2402+
if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
2403+
Tok.is(tok::comma)) {
2404+
Diag(Tok, diag::err_multiple_template_declarators)
2405+
<< (int)TemplateInfo.Kind;
2406+
// SkipUntil(tok::semi);
2407+
}
2408+
23472409
// If we don't have a comma, it is either the end of the list (a ';') or an
23482410
// error, bail out.
23492411
SourceLocation CommaLoc;
@@ -2387,7 +2449,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
23872449
// declarator requires-clause
23882450
if (Tok.is(tok::kw_requires))
23892451
ParseTrailingRequiresClause(D);
2390-
Decl *ThisDecl = ParseDeclarationAfterDeclarator(D);
2452+
Decl *ThisDecl = ParseDeclarationAfterDeclarator(D, TemplateInfo);
23912453
D.complete(ThisDecl);
23922454
if (ThisDecl)
23932455
DeclsInGroup.push_back(ThisDecl);

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3024,7 +3024,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
30243024
// member-declarator-list:
30253025
// member-declarator
30263026
// member-declarator-list ',' member-declarator
3027-
3027+
bool PastFirst = false;
30283028
while (true) {
30293029
InClassInitStyle HasInClassInit = ICIS_NoInit;
30303030
bool HasStaticInitializer = false;
@@ -3167,14 +3167,12 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
31673167

31683168
DeclaratorInfo.complete(ThisDecl);
31693169

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;
3170+
if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && !PastFirst &&
3171+
Tok.is(tok::comma)) {
3172+
Diag(Tok, diag::err_multiple_template_declarators)
3173+
<< (int)TemplateInfo.Kind;
31773174
}
3175+
PastFirst = true;
31783176

31793177
// If we don't have a comma, it is either the end of the list (a ';')
31803178
// or an error, bail out.

clang/lib/Parse/ParseTemplate.cpp

Lines changed: 11 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,10 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
168168
LastParamListWasEmpty),
169169
DeclEnd);
170170

171+
ParsedTemplateInfo TemplateInfo(&ParamLists, isSpecialization,
172+
LastParamListWasEmpty);
171173
return ParseSingleDeclarationAfterTemplate(
172-
Context,
173-
ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty),
174-
ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
174+
Context, TemplateInfo, ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
175175
}
176176

177177
/// Parse a single declaration that declares a template,
@@ -185,7 +185,7 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
185185
///
186186
/// \returns the new declaration.
187187
Decl *Parser::ParseSingleDeclarationAfterTemplate(
188-
DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo,
188+
DeclaratorContext Context, ParsedTemplateInfo &TemplateInfo,
189189
ParsingDeclRAIIObject &DiagsFromTParams, SourceLocation &DeclEnd,
190190
ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
191191
assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
@@ -262,123 +262,12 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
262262
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
263263
ProhibitAttributes(prefixAttrs);
264264

265-
// Parse the declarator.
266-
ParsingDeclarator DeclaratorInfo(*this, DS, prefixAttrs,
267-
(DeclaratorContext)Context);
268-
if (TemplateInfo.TemplateParams)
269-
DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams);
270-
271-
// Turn off usual access checking for template specializations and
272-
// instantiations.
273-
// C++20 [temp.spec] 13.9/6.
274-
// This disables the access checking rules for function template explicit
275-
// instantiation and explicit specialization:
276-
// - parameter-list;
277-
// - template-argument-list;
278-
// - noexcept-specifier;
279-
// - dynamic-exception-specifications (deprecated in C++11, removed since
280-
// C++17).
281-
bool IsTemplateSpecOrInst =
282-
(TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
283-
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
284-
SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst);
285-
286-
ParseDeclarator(DeclaratorInfo);
287-
288-
if (IsTemplateSpecOrInst)
289-
SAC.done();
290-
291-
// Error parsing the declarator?
292-
if (!DeclaratorInfo.hasName()) {
293-
SkipMalformedDecl();
265+
auto DeclGroupPtr =
266+
ParseDeclGroup(DS, Context, prefixAttrs, TemplateInfo, &DeclEnd,
267+
/*FRI=*/nullptr);
268+
if (!DeclGroupPtr || !DeclGroupPtr.get().isSingleDecl())
294269
return nullptr;
295-
}
296-
297-
LateParsedAttrList LateParsedAttrs(true);
298-
if (DeclaratorInfo.isFunctionDeclarator()) {
299-
if (Tok.is(tok::kw_requires)) {
300-
CXXScopeSpec &ScopeSpec = DeclaratorInfo.getCXXScopeSpec();
301-
DeclaratorScopeObj DeclScopeObj(*this, ScopeSpec);
302-
if (ScopeSpec.isValid() &&
303-
Actions.ShouldEnterDeclaratorScope(getCurScope(), ScopeSpec))
304-
DeclScopeObj.EnterDeclaratorScope();
305-
ParseTrailingRequiresClause(DeclaratorInfo);
306-
}
307-
308-
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
309-
}
310-
311-
if (DeclaratorInfo.isFunctionDeclarator() &&
312-
isStartOfFunctionDefinition(DeclaratorInfo)) {
313-
314-
// Function definitions are only allowed at file scope and in C++ classes.
315-
// The C++ inline method definition case is handled elsewhere, so we only
316-
// need to handle the file scope definition case.
317-
if (Context != DeclaratorContext::File) {
318-
Diag(Tok, diag::err_function_definition_not_allowed);
319-
SkipMalformedDecl();
320-
return nullptr;
321-
}
322-
323-
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
324-
// Recover by ignoring the 'typedef'. This was probably supposed to be
325-
// the 'typename' keyword, which we should have already suggested adding
326-
// if it's appropriate.
327-
Diag(DS.getStorageClassSpecLoc(), diag::err_function_declared_typedef)
328-
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
329-
DS.ClearStorageClassSpecs();
330-
}
331-
332-
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
333-
if (DeclaratorInfo.getName().getKind() !=
334-
UnqualifiedIdKind::IK_TemplateId) {
335-
// If the declarator-id is not a template-id, issue a diagnostic and
336-
// recover by ignoring the 'template' keyword.
337-
Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0;
338-
return ParseFunctionDefinition(DeclaratorInfo, ParsedTemplateInfo(),
339-
&LateParsedAttrs);
340-
} else {
341-
SourceLocation LAngleLoc
342-
= PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
343-
Diag(DeclaratorInfo.getIdentifierLoc(),
344-
diag::err_explicit_instantiation_with_definition)
345-
<< SourceRange(TemplateInfo.TemplateLoc)
346-
<< FixItHint::CreateInsertion(LAngleLoc, "<>");
347-
348-
// Recover as if it were an explicit specialization.
349-
TemplateParameterLists FakedParamLists;
350-
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
351-
0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc,
352-
std::nullopt, LAngleLoc, nullptr));
353-
354-
return ParseFunctionDefinition(
355-
DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists,
356-
/*isSpecialization=*/true,
357-
/*lastParameterListWasEmpty=*/true),
358-
&LateParsedAttrs);
359-
}
360-
}
361-
return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo,
362-
&LateParsedAttrs);
363-
}
364-
365-
// Parse this declaration.
366-
Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo,
367-
TemplateInfo);
368-
369-
if (Tok.is(tok::comma)) {
370-
Diag(Tok, diag::err_multiple_template_declarators)
371-
<< (int)TemplateInfo.Kind;
372-
SkipUntil(tok::semi);
373-
return ThisDecl;
374-
}
375-
376-
// Eat the semi colon after the declaration.
377-
ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
378-
if (LateParsedAttrs.size() > 0)
379-
ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false);
380-
DeclaratorInfo.complete(ThisDecl);
381-
return ThisDecl;
270+
return DeclGroupPtr.get().getSingleDecl();
382271
}
383272

384273
/// \brief Parse a single declaration that declares a concept.
@@ -1696,9 +1585,9 @@ Decl *Parser::ParseExplicitInstantiation(DeclaratorContext Context,
16961585
ParsingDeclRAIIObject
16971586
ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent);
16981587

1588+
ParsedTemplateInfo TemplateInfo(ExternLoc, TemplateLoc);
16991589
return ParseSingleDeclarationAfterTemplate(
1700-
Context, ParsedTemplateInfo(ExternLoc, TemplateLoc),
1701-
ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
1590+
Context, TemplateInfo, ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
17021591
}
17031592

17041593
SourceRange Parser::ParsedTemplateInfo::getSourceRange() const {

clang/lib/Parse/Parser.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,8 +1240,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
12401240
Decl *TheDecl = ParseLinkage(DS, DeclaratorContext::File);
12411241
return Actions.ConvertDeclToDeclGroup(TheDecl);
12421242
}
1243-
1244-
return ParseDeclGroup(DS, DeclaratorContext::File, Attrs);
1243+
ParsedTemplateInfo TemplateInfo;
1244+
return ParseDeclGroup(DS, DeclaratorContext::File, Attrs, TemplateInfo);
12451245
}
12461246

12471247
Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(

0 commit comments

Comments
 (0)