diff options
author | Krystian Stasiowski <sdkrystian@gmail.com> | 2024-06-18 13:40:31 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-18 13:40:31 -0400 |
commit | 9a88aa0e2b6d09c7c7932e14224632b2033ad403 (patch) | |
tree | f561bf984f0872e2fbfa5836d8590f60be576d45 /clang/lib/Parse | |
parent | 35a2b60973074ab7b9add53c58acafe166820551 (diff) | |
download | llvm-9a88aa0e2b6d09c7c7932e14224632b2033ad403.zip llvm-9a88aa0e2b6d09c7c7932e14224632b2033ad403.tar.gz llvm-9a88aa0e2b6d09c7c7932e14224632b2033ad403.tar.bz2 |
[Clang][Sema] Diagnose variable template explicit specializations with storage-class-specifiers (#93873)
According to [temp.expl.spec] p2:
> The declaration in an _explicit-specialization_ shall not be an
_export-declaration_. An explicit specialization shall not use a
_storage-class-specifier_ other than `thread_local`.
Clang partially implements this, but a number of issues exist:
1. We don't diagnose class scope explicit specializations of variable
templates with _storage-class-specifiers_, e.g.
```
struct A
{
template<typename T>
static constexpr int x = 0;
template<>
static constexpr int x<void> = 1; // ill-formed, but clang accepts
};
````
2. We incorrectly reject class scope explicit specializations of
variable templates when `static` is not used, e.g.
```
struct A
{
template<typename T>
static constexpr int x = 0;
template<>
constexpr int x<void> = 1; // error: non-static data member cannot be
constexpr; did you intend to make it static?
};
````
3. We don't diagnose dependent class scope explicit specializations of
function templates with storage class specifiers, e.g.
```
template<typename T>
struct A
{
template<typename U>
static void f();
template<>
static void f<int>(); // ill-formed, but clang accepts
};
````
This patch addresses these issues as follows:
- # 1 is fixed by issuing a diagnostic when an explicit
specialization of a variable template has storage class specifier
- # 2 is fixed by considering any non-function declaration with any
template parameter lists at class scope to be a static data member. This
also allows for better error recovery (it's more likely the user
intended to declare a variable template than a "field template").
- # 3 is fixed by checking whether a function template explicit
specialization has a storage class specifier even when the primary
template is not yet known.
One thing to note is that it would be far simpler to diagnose this when
parsing the _decl-specifier-seq_, but such an implementation would
necessitate a refactor of `ParsedTemplateInfo` which I believe to be
outside the scope of this patch.
Diffstat (limited to 'clang/lib/Parse')
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 9a4a777..d02548f 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -3162,7 +3162,8 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration( DeclSpec::SCS_static && DeclaratorInfo.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && - !DS.isFriendSpecified()) { + !DS.isFriendSpecified() && + TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate) { // It's a default member initializer. if (BitfieldSize.get()) Diag(Tok, getLangOpts().CPlusPlus20 @@ -3261,7 +3262,7 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration( } else if (ThisDecl) Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid()); - } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) + } else if (ThisDecl && DeclaratorInfo.isStaticMember()) // No initializer. Actions.ActOnUninitializedDecl(ThisDecl); |