[clang] c5f4619 - [Clang][Parse] Diagnose member template declarations with multiple declarators (#78243)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 1 08:19:09 PST 2024
Author: Krystian Stasiowski
Date: 2024-02-01T11:19:04-05:00
New Revision: c5f461918cece4362fb70c7b16de4e95c1af8e5f
URL: https://github.com/llvm/llvm-project/commit/c5f461918cece4362fb70c7b16de4e95c1af8e5f
DIFF: https://github.com/llvm/llvm-project/commit/c5f461918cece4362fb70c7b16de4e95c1af8e5f.diff
LOG: [Clang][Parse] Diagnose member template declarations with multiple declarators (#78243)
According to [temp.pre] p5:
> In a template-declaration, explicit specialization, or explicit instantiation the init-declarator-list in the declaration shall contain at most one declarator.
A member-declaration that is a template-declaration or explicit-specialization contains a declaration, even though it declares a member. This means it _will_ contain an init-declarator-list (not a member-declarator-list), so [temp.pre] p5 applies.
This diagnoses declarations such as:
```
struct A
{
template<typename T>
static const int x = 0, f(); // error: a template declaration can only declare a single entity
template<typename T>
static const int g(), y = 0; // error: a template declaration can only declare a single entity
};
```
The diagnostic messages are the same as those of the equivalent namespace scope declarations.
Note: since we currently do not diagnose declarations with multiple abbreviated function template declarators at namespace scope e.g., `void f(auto), g(auto);`, so this patch does not add diagnostics for the equivalent member declarations.
This patch also refactors `ParseSingleDeclarationAfterTemplate` (now named `ParseDeclarationAfterTemplate`) to call `ParseDeclGroup` and return the resultant `DeclGroup`.
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Parse/Parser.h
clang/lib/Parse/ParseDecl.cpp
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Parse/ParseTemplate.cpp
clang/lib/Parse/Parser.cpp
clang/test/CXX/temp/p3.cpp
clang/test/OpenMP/declare_simd_messages.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ec9e3ef07057f..efd925e990f43 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -144,6 +144,8 @@ Improvements to Clang's diagnostics
- Clang now applies syntax highlighting to the code snippets it
prints.
+- Clang now diagnoses member template declarations with multiple declarators.
+
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 4a066acf511a1..da18cf88edcc9 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2423,6 +2423,7 @@ class Parser : public CodeCompletionHandler {
bool MightBeDeclarator(DeclaratorContext Context);
DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context,
ParsedAttributes &Attrs,
+ ParsedTemplateInfo &TemplateInfo,
SourceLocation *DeclEnd = nullptr,
ForRangeInit *FRI = nullptr);
Decl *ParseDeclarationAfterDeclarator(Declarator &D,
@@ -3615,16 +3616,15 @@ class Parser : public CodeCompletionHandler {
// C++ 14: Templates [temp]
// C++ 14.1: Template Parameters [temp.param]
- Decl *ParseDeclarationStartingWithTemplate(DeclaratorContext Context,
- SourceLocation &DeclEnd,
- ParsedAttributes &AccessAttrs,
- AccessSpecifier AS = AS_none);
- Decl *ParseTemplateDeclarationOrSpecialization(DeclaratorContext Context,
- SourceLocation &DeclEnd,
- ParsedAttributes &AccessAttrs,
- AccessSpecifier AS);
- Decl *ParseSingleDeclarationAfterTemplate(
- DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo,
+ DeclGroupPtrTy
+ ParseDeclarationStartingWithTemplate(DeclaratorContext Context,
+ SourceLocation &DeclEnd,
+ ParsedAttributes &AccessAttrs);
+ DeclGroupPtrTy ParseTemplateDeclarationOrSpecialization(
+ DeclaratorContext Context, SourceLocation &DeclEnd,
+ ParsedAttributes &AccessAttrs, AccessSpecifier AS);
+ DeclGroupPtrTy ParseDeclarationAfterTemplate(
+ DeclaratorContext Context, ParsedTemplateInfo &TemplateInfo,
ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs, AccessSpecifier AS = AS_none);
bool ParseTemplateParameters(MultiParseScope &TemplateScopes, unsigned Depth,
@@ -3673,12 +3673,12 @@ class Parser : public CodeCompletionHandler {
TemplateTy Template, SourceLocation OpenLoc);
ParsedTemplateArgument ParseTemplateTemplateArgument();
ParsedTemplateArgument ParseTemplateArgument();
- Decl *ParseExplicitInstantiation(DeclaratorContext Context,
- SourceLocation ExternLoc,
- SourceLocation TemplateLoc,
- SourceLocation &DeclEnd,
- ParsedAttributes &AccessAttrs,
- AccessSpecifier AS = AS_none);
+ DeclGroupPtrTy ParseExplicitInstantiation(DeclaratorContext Context,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ SourceLocation &DeclEnd,
+ ParsedAttributes &AccessAttrs,
+ AccessSpecifier AS = AS_none);
// C++2a: Template, concept definition [temp]
Decl *
ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index bcbe2d9c635a6..a186253954f68 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -1916,9 +1916,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
case tok::kw_export:
ProhibitAttributes(DeclAttrs);
ProhibitAttributes(DeclSpecAttrs);
- SingleDecl =
- ParseDeclarationStartingWithTemplate(Context, DeclEnd, DeclAttrs);
- break;
+ return ParseDeclarationStartingWithTemplate(Context, DeclEnd, DeclAttrs);
case tok::kw_inline:
// Could be the start of an inline namespace. Allowed as an ext in C++03.
if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) {
@@ -1994,8 +1992,9 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
ParsingDeclSpec DS(*this);
DS.takeAttributesFrom(DeclSpecAttrs);
+ ParsedTemplateInfo TemplateInfo;
DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(Context);
- ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, DSContext);
+ ParseDeclarationSpecifiers(DS, TemplateInfo, AS_none, DSContext);
// If we had a free-standing type definition with a missing semicolon, we
// may get this far before the problem becomes obvious.
@@ -2027,7 +2026,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
if (DeclSpecStart)
DS.SetRangeStart(*DeclSpecStart);
- return ParseDeclGroup(DS, Context, DeclAttrs, &DeclEnd, FRI);
+ return ParseDeclGroup(DS, Context, DeclAttrs, TemplateInfo, &DeclEnd, FRI);
}
/// Returns true if this might be the start of a declarator, or a common typo
@@ -2184,6 +2183,7 @@ void Parser::SkipMalformedDecl() {
Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
DeclaratorContext Context,
ParsedAttributes &Attrs,
+ ParsedTemplateInfo &TemplateInfo,
SourceLocation *DeclEnd,
ForRangeInit *FRI) {
// Parse the first declarator.
@@ -2193,8 +2193,19 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
ParsedAttributes LocalAttrs(AttrFactory);
LocalAttrs.takeAllFrom(Attrs);
ParsingDeclarator D(*this, DS, LocalAttrs, Context);
+ if (TemplateInfo.TemplateParams)
+ D.setTemplateParameterLists(*TemplateInfo.TemplateParams);
+
+ bool IsTemplateSpecOrInst =
+ (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
+ TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
+ SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst);
+
ParseDeclarator(D);
+ if (IsTemplateSpecOrInst)
+ SAC.done();
+
// Bail out if the first declarator didn't seem well-formed.
if (!D.hasName() && !D.mayOmitIdentifier()) {
SkipMalformedDecl();
@@ -2262,15 +2273,54 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// need to handle the file scope definition case.
if (Context == DeclaratorContext::File) {
if (isStartOfFunctionDefinition(D)) {
+ // C++23 [dcl.typedef] p1:
+ // The typedef specifier shall not be [...], and it shall not be
+ // used in the decl-specifier-seq of a parameter-declaration nor in
+ // the decl-specifier-seq of a function-definition.
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
- Diag(Tok, diag::err_function_declared_typedef);
-
- // Recover by treating the 'typedef' as spurious.
+ // If the user intended to write 'typename', we should have already
+ // suggested adding it elsewhere. In any case, recover by ignoring
+ // 'typedef' and suggest removing it.
+ Diag(DS.getStorageClassSpecLoc(),
+ diag::err_function_declared_typedef)
+ << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
DS.ClearStorageClassSpecs();
}
+ Decl *TheDecl = nullptr;
+
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
+ if (D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) {
+ // If the declarator-id is not a template-id, issue a diagnostic
+ // and recover by ignoring the 'template' keyword.
+ Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0;
+ TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(),
+ &LateParsedAttrs);
+ } else {
+ SourceLocation LAngleLoc =
+ PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
+ Diag(D.getIdentifierLoc(),
+ diag::err_explicit_instantiation_with_definition)
+ << SourceRange(TemplateInfo.TemplateLoc)
+ << FixItHint::CreateInsertion(LAngleLoc, "<>");
+
+ // Recover as if it were an explicit specialization.
+ TemplateParameterLists FakedParamLists;
+ FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc,
+ std::nullopt, LAngleLoc, nullptr));
+
+ TheDecl = ParseFunctionDefinition(
+ D,
+ ParsedTemplateInfo(&FakedParamLists,
+ /*isSpecialization=*/true,
+ /*lastParameterListWasEmpty=*/true),
+ &LateParsedAttrs);
+ }
+ } else {
+ TheDecl =
+ ParseFunctionDefinition(D, TemplateInfo, &LateParsedAttrs);
+ }
- Decl *TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(),
- &LateParsedAttrs);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
@@ -2360,8 +2410,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
}
SmallVector<Decl *, 8> DeclsInGroup;
- Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(
- D, ParsedTemplateInfo(), FRI);
+ Decl *FirstDecl =
+ ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo, FRI);
if (LateParsedAttrs.size() > 0)
ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false);
D.complete(FirstDecl);
@@ -2384,6 +2434,16 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
break;
}
+ // C++23 [temp.pre]p5:
+ // In a template-declaration, explicit specialization, or explicit
+ // instantiation the init-declarator-list in the declaration shall
+ // contain at most one declarator.
+ if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
+ D.isFirstDeclarator()) {
+ Diag(CommaLoc, diag::err_multiple_template_declarators)
+ << TemplateInfo.Kind;
+ }
+
// Parse the next declarator.
D.clear();
D.setCommaLoc(CommaLoc);
@@ -2413,7 +2473,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// declarator requires-clause
if (Tok.is(tok::kw_requires))
ParseTrailingRequiresClause(D);
- Decl *ThisDecl = ParseDeclarationAfterDeclarator(D);
+ Decl *ThisDecl = ParseDeclarationAfterDeclarator(D, TemplateInfo);
D.complete(ThisDecl);
if (ThisDecl)
DeclsInGroup.push_back(ThisDecl);
@@ -6526,6 +6586,17 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
/*ObjectHasErrors=*/false, EnteringContext);
}
+ // C++23 [basic.scope.namespace]p1:
+ // For each non-friend redeclaration or specialization whose target scope
+ // is or is contained by the scope, the portion after the declarator-id,
+ // class-head-name, or enum-head-name is also included in the scope.
+ // C++23 [basic.scope.class]p1:
+ // For each non-friend redeclaration or specialization whose target scope
+ // is or is contained by the scope, the portion after the declarator-id,
+ // class-head-name, or enum-head-name is also included in the scope.
+ //
+ // FIXME: We should not be doing this for friend declarations; they have
+ // their own special lookup semantics specified by [basic.lookup.unqual]p6.
if (D.getCXXScopeSpec().isValid()) {
if (Actions.ShouldEnterDeclaratorScope(getCurScope(),
D.getCXXScopeSpec()))
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 06ccc1e3d04e9..cdbfbb1bc9fff 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -2855,7 +2855,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
// static_assert-declaration. A templated static_assert declaration is
- // diagnosed in Parser::ParseSingleDeclarationAfterTemplate.
+ // diagnosed in Parser::ParseDeclarationAfterTemplate.
if (!TemplateInfo.Kind &&
Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
SourceLocation DeclEnd;
@@ -2868,9 +2868,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
"Nested template improperly parsed?");
ObjCDeclContextSwitch ObjCDC(*this);
SourceLocation DeclEnd;
- return DeclGroupPtrTy::make(
- DeclGroupRef(ParseTemplateDeclarationOrSpecialization(
- DeclaratorContext::Member, DeclEnd, AccessAttrs, AS)));
+ return ParseTemplateDeclarationOrSpecialization(DeclaratorContext::Member,
+ DeclEnd, AccessAttrs, AS);
}
// Handle: member-declaration ::= '__extension__' member-declaration
@@ -3279,6 +3278,16 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
break;
}
+ // C++23 [temp.pre]p5:
+ // In a template-declaration, explicit specialization, or explicit
+ // instantiation the init-declarator-list in the declaration shall
+ // contain at most one declarator.
+ if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
+ DeclaratorInfo.isFirstDeclarator()) {
+ Diag(CommaLoc, diag::err_multiple_template_declarators)
+ << TemplateInfo.Kind;
+ }
+
// Parse the next declarator.
DeclaratorInfo.clear();
VS.clear();
@@ -4228,6 +4237,24 @@ void Parser::ParseTrailingRequiresClause(Declarator &D) {
SourceLocation RequiresKWLoc = ConsumeToken();
+ // C++23 [basic.scope.namespace]p1:
+ // For each non-friend redeclaration or specialization whose target scope
+ // is or is contained by the scope, the portion after the declarator-id,
+ // class-head-name, or enum-head-name is also included in the scope.
+ // C++23 [basic.scope.class]p1:
+ // For each non-friend redeclaration or specialization whose target scope
+ // is or is contained by the scope, the portion after the declarator-id,
+ // class-head-name, or enum-head-name is also included in the scope.
+ //
+ // FIXME: We should really be calling ParseTrailingRequiresClause in
+ // ParseDirectDeclarator, when we are already in the declarator scope.
+ // This would also correctly suppress access checks for specializations
+ // and explicit instantiations, which we currently do not do.
+ CXXScopeSpec &SS = D.getCXXScopeSpec();
+ DeclaratorScopeObj DeclScopeObj(*this, SS);
+ if (SS.isValid() && Actions.ShouldEnterDeclaratorScope(getCurScope(), SS))
+ DeclScopeObj.EnterDeclaratorScope();
+
ExprResult TrailingRequiresClause;
ParseScope ParamScope(this, Scope::DeclScope |
Scope::FunctionDeclarationScope |
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 64fe4d50bba27..d4897f8f66072 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -36,17 +36,19 @@ unsigned Parser::ReenterTemplateScopes(MultiParseScope &S, Decl *D) {
/// Parse a template declaration, explicit instantiation, or
/// explicit specialization.
-Decl *Parser::ParseDeclarationStartingWithTemplate(
- DeclaratorContext Context, SourceLocation &DeclEnd,
- ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
+Parser::DeclGroupPtrTy
+Parser::ParseDeclarationStartingWithTemplate(DeclaratorContext Context,
+ SourceLocation &DeclEnd,
+ ParsedAttributes &AccessAttrs) {
ObjCDeclContextSwitch ObjCDC(*this);
if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) {
return ParseExplicitInstantiation(Context, SourceLocation(), ConsumeToken(),
- DeclEnd, AccessAttrs, AS);
+ DeclEnd, AccessAttrs,
+ AccessSpecifier::AS_none);
}
return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs,
- AS);
+ AccessSpecifier::AS_none);
}
/// Parse a template declaration or an explicit specialization.
@@ -73,7 +75,7 @@ Decl *Parser::ParseDeclarationStartingWithTemplate(
///
/// explicit-specialization: [ C++ temp.expl.spec]
/// 'template' '<' '>' declaration
-Decl *Parser::ParseTemplateDeclarationOrSpecialization(
+Parser::DeclGroupPtrTy Parser::ParseTemplateDeclarationOrSpecialization(
DeclaratorContext Context, SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
assert(Tok.isOneOf(tok::kw_export, tok::kw_template) &&
@@ -161,17 +163,16 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get()));
} while (Tok.isOneOf(tok::kw_export, tok::kw_template));
+ ParsedTemplateInfo TemplateInfo(&ParamLists, isSpecialization,
+ LastParamListWasEmpty);
+
// Parse the actual template declaration.
if (Tok.is(tok::kw_concept))
- return ParseConceptDefinition(
- ParsedTemplateInfo(&ParamLists, isSpecialization,
- LastParamListWasEmpty),
- DeclEnd);
-
- return ParseSingleDeclarationAfterTemplate(
- Context,
- ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty),
- ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
+ return Actions.ConvertDeclToDeclGroup(
+ ParseConceptDefinition(TemplateInfo, DeclEnd));
+
+ return ParseDeclarationAfterTemplate(
+ Context, TemplateInfo, ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
}
/// Parse a single declaration that declares a template,
@@ -184,8 +185,8 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
/// declaration. Will be AS_none for namespace-scope declarations.
///
/// \returns the new declaration.
-Decl *Parser::ParseSingleDeclarationAfterTemplate(
- DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo,
+Parser::DeclGroupPtrTy Parser::ParseDeclarationAfterTemplate(
+ DeclaratorContext Context, ParsedTemplateInfo &TemplateInfo,
ParsingDeclRAIIObject &DiagsFromTParams, SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
@@ -196,37 +197,29 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
Diag(Tok.getLocation(), diag::err_templated_invalid_declaration)
<< TemplateInfo.getSourceRange();
// Parse the static_assert declaration to improve error recovery.
- return ParseStaticAssertDeclaration(DeclEnd);
+ return Actions.ConvertDeclToDeclGroup(
+ ParseStaticAssertDeclaration(DeclEnd));
}
- if (Context == DeclaratorContext::Member) {
- // We are parsing a member template.
- DeclGroupPtrTy D = ParseCXXClassMemberDeclaration(
- AS, AccessAttrs, TemplateInfo, &DiagsFromTParams);
+ // We are parsing a member template.
+ if (Context == DeclaratorContext::Member)
+ return ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo,
+ &DiagsFromTParams);
- if (!D || !D.get().isSingleDecl())
- return nullptr;
- return D.get().getSingleDecl();
- }
-
- ParsedAttributes prefixAttrs(AttrFactory);
+ ParsedAttributes DeclAttrs(AttrFactory);
ParsedAttributes DeclSpecAttrs(AttrFactory);
// GNU attributes are applied to the declaration specification while the
// standard attributes are applied to the declaration. We parse the two
// attribute sets into
diff erent containters so we can apply them during
// the regular parsing process.
- while (MaybeParseCXX11Attributes(prefixAttrs) ||
+ while (MaybeParseCXX11Attributes(DeclAttrs) ||
MaybeParseGNUAttributes(DeclSpecAttrs))
;
- if (Tok.is(tok::kw_using)) {
- auto usingDeclPtr = ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
- prefixAttrs);
- if (!usingDeclPtr || !usingDeclPtr.get().isSingleDecl())
- return nullptr;
- return usingDeclPtr.get().getSingleDecl();
- }
+ if (Tok.is(tok::kw_using))
+ return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
+ DeclAttrs);
// Parse the declaration specifiers, stealing any diagnostics from
// the template parameters.
@@ -239,7 +232,7 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
getDeclSpecContextFromDeclaratorContext(Context));
if (Tok.is(tok::semi)) {
- ProhibitAttributes(prefixAttrs);
+ ProhibitAttributes(DeclAttrs);
DeclEnd = ConsumeToken();
RecordDecl *AnonRecord = nullptr;
Decl *Decl = Actions.ParsedFreeStandingDeclSpec(
@@ -252,7 +245,7 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
assert(!AnonRecord &&
"Anonymous unions/structs should not be valid with template");
DS.complete(Decl);
- return Decl;
+ return Actions.ConvertDeclToDeclGroup(Decl);
}
if (DS.hasTagDefinition())
@@ -260,125 +253,9 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
// Move the attributes from the prefix into the DS.
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
- ProhibitAttributes(prefixAttrs);
-
- // Parse the declarator.
- ParsingDeclarator DeclaratorInfo(*this, DS, prefixAttrs,
- (DeclaratorContext)Context);
- if (TemplateInfo.TemplateParams)
- DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams);
-
- // Turn off usual access checking for template specializations and
- // instantiations.
- // C++20 [temp.spec] 13.9/6.
- // This disables the access checking rules for function template explicit
- // instantiation and explicit specialization:
- // - parameter-list;
- // - template-argument-list;
- // - noexcept-specifier;
- // - dynamic-exception-specifications (deprecated in C++11, removed since
- // C++17).
- bool IsTemplateSpecOrInst =
- (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
- TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
- SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst);
-
- ParseDeclarator(DeclaratorInfo);
-
- if (IsTemplateSpecOrInst)
- SAC.done();
-
- // Error parsing the declarator?
- if (!DeclaratorInfo.hasName()) {
- SkipMalformedDecl();
- return nullptr;
- }
-
- LateParsedAttrList LateParsedAttrs(true);
- if (DeclaratorInfo.isFunctionDeclarator()) {
- if (Tok.is(tok::kw_requires)) {
- CXXScopeSpec &ScopeSpec = DeclaratorInfo.getCXXScopeSpec();
- DeclaratorScopeObj DeclScopeObj(*this, ScopeSpec);
- if (ScopeSpec.isValid() &&
- Actions.ShouldEnterDeclaratorScope(getCurScope(), ScopeSpec))
- DeclScopeObj.EnterDeclaratorScope();
- ParseTrailingRequiresClause(DeclaratorInfo);
- }
-
- MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
- }
-
- if (DeclaratorInfo.isFunctionDeclarator() &&
- isStartOfFunctionDefinition(DeclaratorInfo)) {
+ ProhibitAttributes(DeclAttrs);
- // Function definitions are only allowed at file scope and in C++ classes.
- // The C++ inline method definition case is handled elsewhere, so we only
- // need to handle the file scope definition case.
- if (Context != DeclaratorContext::File) {
- Diag(Tok, diag::err_function_definition_not_allowed);
- SkipMalformedDecl();
- return nullptr;
- }
-
- if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
- // Recover by ignoring the 'typedef'. This was probably supposed to be
- // the 'typename' keyword, which we should have already suggested adding
- // if it's appropriate.
- Diag(DS.getStorageClassSpecLoc(), diag::err_function_declared_typedef)
- << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
- DS.ClearStorageClassSpecs();
- }
-
- if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
- if (DeclaratorInfo.getName().getKind() !=
- UnqualifiedIdKind::IK_TemplateId) {
- // If the declarator-id is not a template-id, issue a diagnostic and
- // recover by ignoring the 'template' keyword.
- Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0;
- return ParseFunctionDefinition(DeclaratorInfo, ParsedTemplateInfo(),
- &LateParsedAttrs);
- } else {
- SourceLocation LAngleLoc
- = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
- Diag(DeclaratorInfo.getIdentifierLoc(),
- diag::err_explicit_instantiation_with_definition)
- << SourceRange(TemplateInfo.TemplateLoc)
- << FixItHint::CreateInsertion(LAngleLoc, "<>");
-
- // Recover as if it were an explicit specialization.
- TemplateParameterLists FakedParamLists;
- FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
- 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc,
- std::nullopt, LAngleLoc, nullptr));
-
- return ParseFunctionDefinition(
- DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists,
- /*isSpecialization=*/true,
- /*lastParameterListWasEmpty=*/true),
- &LateParsedAttrs);
- }
- }
- return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo,
- &LateParsedAttrs);
- }
-
- // Parse this declaration.
- Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo,
- TemplateInfo);
-
- if (Tok.is(tok::comma)) {
- Diag(Tok, diag::err_multiple_template_declarators)
- << (int)TemplateInfo.Kind;
- SkipUntil(tok::semi);
- return ThisDecl;
- }
-
- // Eat the semi colon after the declaration.
- ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
- if (LateParsedAttrs.size() > 0)
- ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false);
- DeclaratorInfo.complete(ThisDecl);
- return ThisDecl;
+ return ParseDeclGroup(DS, Context, DeclAttrs, TemplateInfo, &DeclEnd);
}
/// \brief Parse a single declaration that declares a concept.
@@ -1686,19 +1563,16 @@ bool Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
/// 'extern' [opt] 'template' declaration
///
/// Note that the 'extern' is a GNU extension and C++11 feature.
-Decl *Parser::ParseExplicitInstantiation(DeclaratorContext Context,
- SourceLocation ExternLoc,
- SourceLocation TemplateLoc,
- SourceLocation &DeclEnd,
- ParsedAttributes &AccessAttrs,
- AccessSpecifier AS) {
+Parser::DeclGroupPtrTy Parser::ParseExplicitInstantiation(
+ DeclaratorContext Context, SourceLocation ExternLoc,
+ SourceLocation TemplateLoc, SourceLocation &DeclEnd,
+ ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
// This isn't really required here.
ParsingDeclRAIIObject
ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent);
-
- return ParseSingleDeclarationAfterTemplate(
- Context, ParsedTemplateInfo(ExternLoc, TemplateLoc),
- ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
+ ParsedTemplateInfo TemplateInfo(ExternLoc, TemplateLoc);
+ return ParseDeclarationAfterTemplate(
+ Context, TemplateInfo, ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
}
SourceRange Parser::ParsedTemplateInfo::getSourceRange() const {
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 3dfd44677e5a2..2dd4a73bfbc26 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1040,8 +1040,8 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
diag::warn_cxx98_compat_extern_template :
diag::ext_extern_template) << SourceRange(ExternLoc, TemplateLoc);
SourceLocation DeclEnd;
- return Actions.ConvertDeclToDeclGroup(ParseExplicitInstantiation(
- DeclaratorContext::File, ExternLoc, TemplateLoc, DeclEnd, Attrs));
+ return ParseExplicitInstantiation(DeclaratorContext::File, ExternLoc,
+ TemplateLoc, DeclEnd, Attrs);
}
goto dont_know;
@@ -1143,9 +1143,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
DS.SetRangeEnd(DeclSpecAttrs.Range.getEnd());
DS.takeAttributesFrom(DeclSpecAttrs);
+ ParsedTemplateInfo TemplateInfo;
MaybeParseMicrosoftAttributes(DS.getAttributes());
// Parse the common declaration-specifiers piece.
- ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS,
+ ParseDeclarationSpecifiers(DS, TemplateInfo, AS,
DeclSpecContext::DSC_top_level);
// If we had a free-standing type definition with a missing semicolon, we
@@ -1241,7 +1242,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
- return ParseDeclGroup(DS, DeclaratorContext::File, Attrs);
+ return ParseDeclGroup(DS, DeclaratorContext::File, Attrs, TemplateInfo);
}
Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(
diff --git a/clang/test/CXX/temp/p3.cpp b/clang/test/CXX/temp/p3.cpp
index b708c613d352d..9e561d0b9a83b 100644
--- a/clang/test/CXX/temp/p3.cpp
+++ b/clang/test/CXX/temp/p3.cpp
@@ -15,3 +15,9 @@ template<typename T> struct B { } f(); // expected-error {{expected ';' after st
template<typename T> struct C { } // expected-error {{expected ';' after struct}}
A<int> c;
+
+struct D {
+ template<typename T> static const int x = 0, f(); // expected-error {{can only declare a single entity}}
+
+ template<typename T> static const int g(), y = 0; // expected-error {{can only declare a single entity}}
+};
diff --git a/clang/test/OpenMP/declare_simd_messages.cpp b/clang/test/OpenMP/declare_simd_messages.cpp
index dd24322694b69..fea045400e1fa 100644
--- a/clang/test/OpenMP/declare_simd_messages.cpp
+++ b/clang/test/OpenMP/declare_simd_messages.cpp
@@ -33,10 +33,9 @@ int main();
int main();
struct A {
-// expected-error at +1 {{function declaration is expected after 'declare simd' directive}}
#pragma omp declare simd
template<typename T>
- T infunc1(T a), infunc2(T a);
+ T infunc1(T a);
};
// expected-error at +1 {{single declaration is expected after 'declare simd' directive}}
More information about the cfe-commits
mailing list