-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[Clang][Parse] Diagnose member template declarations with multiple declarators #78243
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Ping @erichkeane |
@llvm/pr-subscribers-clang Author: Krystian Stasiowski (sdkrystian) ChangesAccording to [[temp.pre] p5](http://eel.is/c++draft/temp.pre#5): 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](http://eel.is/c++draft/temp.pre#5) 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., Full diff: https://github.com/llvm/llvm-project/pull/78243.diff 4 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ea57769a4a5795..54debc4d40e945 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -555,6 +555,7 @@ Improvements to Clang's diagnostics
- Clang now diagnoses unexpanded packs within the template argument lists of function template specializations.
- Clang now diagnoses attempts to bind a bitfield to an NTTP of a reference type as erroneous
converted constant expression and not as a reference to subobject.
+- Clang now diagnoses member template declarations with multiple declarators.
Improvements to Clang's time-trace
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 5576be9e717a9b..36a9ef199a9588 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -3167,6 +3167,15 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
DeclaratorInfo.complete(ThisDecl);
+ if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) {
+ if (Tok.is(tok::comma)) {
+ Diag(Tok, diag::err_multiple_template_declarators)
+ << (int)TemplateInfo.Kind;
+ SkipUntil(tok::semi, StopBeforeMatch);
+ }
+ break;
+ }
+
// If we don't have a comma, it is either the end of the list (a ';')
// or an error, bail out.
SourceLocation CommaLoc;
diff --git a/clang/test/CXX/temp/p3.cpp b/clang/test/CXX/temp/p3.cpp
index b708c613d352d2..9e561d0b9a83b2 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 dd24322694b69f..fea045400e1faf 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@+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@+1 {{single declaration is expected after 'declare simd' directive}}
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
44c582f
to
b5d814a
Compare
clang/lib/Parse/ParseDeclCXX.cpp
Outdated
if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) { | ||
if (Tok.is(tok::comma)) { | ||
Diag(Tok, diag::err_multiple_template_declarators) | ||
<< (int)TemplateInfo.Kind; | ||
SkipUntil(tok::semi, StopBeforeMatch); | ||
} | ||
break; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure it make sense to do that in the parser.
Can we maybe to that in FinalizeDeclaratorGroup
?
At that point we should have fully formed Decl
s and we can check whether they are templates
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cor3ntin We diagnose namespace scope template/explicit specialization/explicit instantiation declarations with multiple declarators in the parser as well... is there a reason not to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The 'later' we do these sort of diagnostics, the better we are at recovering from them, and the better the diagnostics can be. IMO, if this is possible, putting this in FinalizeDeclaratorGroup makes a lot more sense here.
At least that way, we could recover and pretend one of those are the 'right' template that we intend to declare.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about issuing the diagnostics in the parser, but instead of skipping to the semicolon we just continue parsing? That way the diagnostics are issued in lexical order when a declaration with multiple errors is encountered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a commit which issues a diagnostic from the parser when a second declarator is encountered for templates, and then have ParseSingleDeclarationAfterTemplate
call ParseDeclGroup
... let me know if y'all think this approach is worth pursuing
f8ba2f5
to
27ec7b3
Compare
27ec7b3
to
f9f50a2
Compare
@erichkeane I have refactored With respect to moving the point of diagnosis to |
f9f50a2
to
35be507
Compare
Ping @cor3ntin |
35be507
to
bba768b
Compare
Ping @erichkeane |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this looks fine now... WDYT @cor3ntin ?
bba768b
to
945fdf5
Compare
945fdf5
to
07999d2
Compare
…clarators (llvm#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`.
…clarators (llvm#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`.
…clarators (llvm#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`.
According to [temp.pre] p5:
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:
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);
, I did not add diagnostics for the equivalent member declarations.