Skip to content

Commit 351d16f

Browse files
committed
[FOLD]
1 parent b3e6fde commit 351d16f

File tree

7 files changed

+370
-111
lines changed

7 files changed

+370
-111
lines changed

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3162,7 +3162,8 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration(
31623162
DeclSpec::SCS_static &&
31633163
DeclaratorInfo.getDeclSpec().getStorageClassSpec() !=
31643164
DeclSpec::SCS_typedef &&
3165-
!DS.isFriendSpecified()) {
3165+
!DS.isFriendSpecified() &&
3166+
TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate) {
31663167
// It's a default member initializer.
31673168
if (BitfieldSize.get())
31683169
Diag(Tok, getLangOpts().CPlusPlus20

clang/lib/Sema/DeclSpec.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ bool Declarator::isDeclarationOfFunction() const {
416416
bool Declarator::isStaticMember() {
417417
assert(getContext() == DeclaratorContext::Member);
418418
return getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
419+
(!isDeclarationOfFunction() && !getTemplateParameterLists().empty()) ||
419420
(getName().getKind() == UnqualifiedIdKind::IK_OperatorFunctionId &&
420421
CXXMethodDecl::isStaticOverloadedOperator(
421422
getName().OperatorFunctionId.Operator));

clang/lib/Sema/SemaDecl.cpp

Lines changed: 115 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -7602,89 +7602,16 @@ NamedDecl *Sema::ActOnVariableDeclarator(
76027602
NTCUC_AutoVar, NTCUK_Destruct);
76037603
} else {
76047604
bool Invalid = false;
7605-
7606-
if (DC->isRecord() && !CurContext->isRecord()) {
7607-
// This is an out-of-line definition of a static data member.
7608-
switch (SC) {
7609-
case SC_None:
7610-
break;
7611-
case SC_Static:
7612-
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
7613-
diag::err_static_out_of_line)
7614-
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
7615-
break;
7616-
case SC_Auto:
7617-
case SC_Register:
7618-
case SC_Extern:
7619-
// [dcl.stc] p2: The auto or register specifiers shall be applied only
7620-
// to names of variables declared in a block or to function parameters.
7621-
// [dcl.stc] p6: The extern specifier cannot be used in the declaration
7622-
// of class members
7623-
7624-
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
7625-
diag::err_storage_class_for_static_member)
7626-
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
7627-
break;
7628-
case SC_PrivateExtern:
7629-
llvm_unreachable("C storage class in c++!");
7630-
}
7631-
}
7632-
7633-
if (SC == SC_Static && CurContext->isRecord()) {
7634-
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
7635-
// Walk up the enclosing DeclContexts to check for any that are
7636-
// incompatible with static data members.
7637-
const DeclContext *FunctionOrMethod = nullptr;
7638-
const CXXRecordDecl *AnonStruct = nullptr;
7639-
for (DeclContext *Ctxt = DC; Ctxt; Ctxt = Ctxt->getParent()) {
7640-
if (Ctxt->isFunctionOrMethod()) {
7641-
FunctionOrMethod = Ctxt;
7642-
break;
7643-
}
7644-
const CXXRecordDecl *ParentDecl = dyn_cast<CXXRecordDecl>(Ctxt);
7645-
if (ParentDecl && !ParentDecl->getDeclName()) {
7646-
AnonStruct = ParentDecl;
7647-
break;
7648-
}
7649-
}
7650-
if (FunctionOrMethod) {
7651-
// C++ [class.static.data]p5: A local class shall not have static data
7652-
// members.
7653-
Diag(D.getIdentifierLoc(),
7654-
diag::err_static_data_member_not_allowed_in_local_class)
7655-
<< Name << RD->getDeclName()
7656-
<< llvm::to_underlying(RD->getTagKind());
7657-
} else if (AnonStruct) {
7658-
// C++ [class.static.data]p4: Unnamed classes and classes contained
7659-
// directly or indirectly within unnamed classes shall not contain
7660-
// static data members.
7661-
Diag(D.getIdentifierLoc(),
7662-
diag::err_static_data_member_not_allowed_in_anon_struct)
7663-
<< Name << llvm::to_underlying(AnonStruct->getTagKind());
7664-
Invalid = true;
7665-
} else if (RD->isUnion()) {
7666-
// C++98 [class.union]p1: If a union contains a static data member,
7667-
// the program is ill-formed. C++11 drops this restriction.
7668-
Diag(D.getIdentifierLoc(),
7669-
getLangOpts().CPlusPlus11
7670-
? diag::warn_cxx98_compat_static_data_member_in_union
7671-
: diag::ext_static_data_member_in_union) << Name;
7672-
}
7673-
}
7674-
}
7675-
76767605
// Match up the template parameter lists with the scope specifier, then
76777606
// determine whether we have a template or a template specialization.
7678-
bool InvalidScope = false;
76797607
TemplateParams = MatchTemplateParametersToScopeSpecifier(
76807608
D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
76817609
D.getCXXScopeSpec(),
76827610
D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
76837611
? D.getName().TemplateId
76847612
: nullptr,
76857613
TemplateParamLists,
7686-
/*never a friend*/ false, IsMemberSpecialization, InvalidScope);
7687-
Invalid |= InvalidScope;
7614+
/*never a friend*/ false, IsMemberSpecialization, Invalid);
76887615

76897616
if (TemplateParams) {
76907617
if (!TemplateParams->size() &&
@@ -7716,14 +7643,6 @@ NamedDecl *Sema::ActOnVariableDeclarator(
77167643
? diag::warn_cxx11_compat_variable_template
77177644
: diag::ext_variable_template);
77187645
}
7719-
7720-
if (CurContext->isRecord() && SC != SC_Static && (IsVariableTemplate || IsPartialSpecialization)) {
7721-
// There is no such thing as a member field template.
7722-
Diag(D.getIdentifierLoc(), diag::err_template_member)
7723-
<< II << TemplateParams->getSourceRange();
7724-
// Recover by pretending this is a static data member template.
7725-
SC = SC_Static;
7726-
}
77277646
}
77287647
} else {
77297648
// Check that we can declare a member specialization here.
@@ -7735,6 +7654,88 @@ NamedDecl *Sema::ActOnVariableDeclarator(
77357654
"should have a 'template<>' for this decl");
77367655
}
77377656

7657+
if (SC != SC_None && ((IsVariableTemplateSpecialization && !IsPartialSpecialization) || IsMemberSpecialization)) {
7658+
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
7659+
diag::ext_explicit_specialization_storage_class)
7660+
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
7661+
}
7662+
7663+
if (CurContext->isRecord()) {
7664+
if (SC == SC_Static) {
7665+
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
7666+
// Walk up the enclosing DeclContexts to check for any that are
7667+
// incompatible with static data members.
7668+
const DeclContext *FunctionOrMethod = nullptr;
7669+
const CXXRecordDecl *AnonStruct = nullptr;
7670+
for (DeclContext *Ctxt = DC; Ctxt; Ctxt = Ctxt->getParent()) {
7671+
if (Ctxt->isFunctionOrMethod()) {
7672+
FunctionOrMethod = Ctxt;
7673+
break;
7674+
}
7675+
const CXXRecordDecl *ParentDecl = dyn_cast<CXXRecordDecl>(Ctxt);
7676+
if (ParentDecl && !ParentDecl->getDeclName()) {
7677+
AnonStruct = ParentDecl;
7678+
break;
7679+
}
7680+
}
7681+
if (FunctionOrMethod) {
7682+
// C++ [class.static.data]p5: A local class shall not have static data
7683+
// members.
7684+
Diag(D.getIdentifierLoc(),
7685+
diag::err_static_data_member_not_allowed_in_local_class)
7686+
<< Name << RD->getDeclName()
7687+
<< llvm::to_underlying(RD->getTagKind());
7688+
} else if (AnonStruct) {
7689+
// C++ [class.static.data]p4: Unnamed classes and classes contained
7690+
// directly or indirectly within unnamed classes shall not contain
7691+
// static data members.
7692+
Diag(D.getIdentifierLoc(),
7693+
diag::err_static_data_member_not_allowed_in_anon_struct)
7694+
<< Name << llvm::to_underlying(AnonStruct->getTagKind());
7695+
Invalid = true;
7696+
} else if (RD->isUnion()) {
7697+
// C++98 [class.union]p1: If a union contains a static data member,
7698+
// the program is ill-formed. C++11 drops this restriction.
7699+
Diag(D.getIdentifierLoc(),
7700+
getLangOpts().CPlusPlus11
7701+
? diag::warn_cxx98_compat_static_data_member_in_union
7702+
: diag::ext_static_data_member_in_union) << Name;
7703+
}
7704+
}
7705+
} else if (IsVariableTemplate || IsPartialSpecialization) {
7706+
// There is no such thing as a member field template.
7707+
Diag(D.getIdentifierLoc(), diag::err_template_member)
7708+
<< II << TemplateParams->getSourceRange();
7709+
// Recover by pretending this is a static data member template.
7710+
SC = SC_Static;
7711+
}
7712+
} else if (DC->isRecord()) {
7713+
// This is an out-of-line definition of a static data member.
7714+
switch (SC) {
7715+
case SC_None:
7716+
break;
7717+
case SC_Static:
7718+
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
7719+
diag::err_static_out_of_line)
7720+
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
7721+
break;
7722+
case SC_Auto:
7723+
case SC_Register:
7724+
case SC_Extern:
7725+
// [dcl.stc] p2: The auto or register specifiers shall be applied only
7726+
// to names of variables declared in a block or to function parameters.
7727+
// [dcl.stc] p6: The extern specifier cannot be used in the declaration
7728+
// of class members
7729+
7730+
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
7731+
diag::err_storage_class_for_static_member)
7732+
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
7733+
break;
7734+
case SC_PrivateExtern:
7735+
llvm_unreachable("C storage class in c++!");
7736+
}
7737+
}
7738+
77387739
if (IsVariableTemplateSpecialization) {
77397740
SourceLocation TemplateKWLoc =
77407741
TemplateParamLists.size() > 0
@@ -10211,26 +10212,37 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
1021110212
NewFD->setImplicitlyInline(ImplicitInlineCXX20);
1021210213
}
1021310214

10214-
if (SC == SC_Static && isa<CXXMethodDecl>(NewFD) &&
10215-
!CurContext->isRecord()) {
10216-
// C++ [class.static]p1:
10217-
// A data or function member of a class may be declared static
10218-
// in a class definition, in which case it is a static member of
10219-
// the class.
10220-
10221-
// Complain about the 'static' specifier if it's on an out-of-line
10222-
// member function definition.
10223-
10224-
// MSVC permits the use of a 'static' storage specifier on an out-of-line
10225-
// member function template declaration and class member template
10226-
// declaration (MSVC versions before 2015), warn about this.
10227-
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
10228-
((!getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) &&
10229-
cast<CXXRecordDecl>(DC)->getDescribedClassTemplate()) ||
10230-
(getLangOpts().MSVCCompat && NewFD->getDescribedFunctionTemplate()))
10231-
? diag::ext_static_out_of_line : diag::err_static_out_of_line)
10232-
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
10215+
if (!isFriend && SC != SC_None) {
10216+
if (isFunctionTemplateSpecialization || isMemberSpecialization) {
10217+
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
10218+
diag::ext_explicit_specialization_storage_class)
10219+
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
10220+
} else if (SC == SC_Static && !CurContext->isRecord() && DC->isRecord()) {
10221+
assert(isa<CXXMethodDecl>(NewFD) && "Out-of-line member function should be a CXXMethodDecl");
10222+
// C++ [class.static]p1:
10223+
// A data or function member of a class may be declared static
10224+
// in a class definition, in which case it is a static member of
10225+
// the class.
10226+
10227+
// Complain about the 'static' specifier if it's on an out-of-line
10228+
// member function definition.
10229+
10230+
// MSVC permits the use of a 'static' storage specifier on an out-of-line
10231+
// member function template declaration and class member template
10232+
// declaration (MSVC versions before 2015), warn about this.
10233+
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
10234+
((!getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) &&
10235+
cast<CXXRecordDecl>(DC)->getDescribedClassTemplate()) ||
10236+
(getLangOpts().MSVCCompat && NewFD->getDescribedFunctionTemplate()))
10237+
? diag::ext_static_out_of_line : diag::err_static_out_of_line)
10238+
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
10239+
}
10240+
}
10241+
#if 0
10242+
if (SC != SC_None && !isFriend && ) {
10243+
} else if (SC == SC_Static && isa<CXXMethodDecl>(NewFD) && !CurContext->isRecord()) {
1023310244
}
10245+
#endif
1023410246

1023510247
// C++11 [except.spec]p15:
1023610248
// A deallocation function with no exception-specification is treated
@@ -10598,6 +10610,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
1059810610
NewFD->setInvalidDecl();
1059910611
}
1060010612

10613+
#if 0
1060110614
// C++ [dcl.stc]p1:
1060210615
// A storage-class-specifier shall not be specified in an explicit
1060310616
// specialization (14.7.3)
@@ -10618,6 +10631,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
1061810631
<< FixItHint::CreateRemoval(
1061910632
D.getDeclSpec().getStorageClassSpecLoc());
1062010633
}
10634+
#endif
1062110635
} else if (isMemberSpecialization && isa<CXXMethodDecl>(NewFD)) {
1062210636
if (CheckMemberSpecialization(NewFD, Previous))
1062310637
NewFD->setInvalidDecl();

clang/test/CXX/drs/cwg7xx.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ namespace cwg727 { // cwg727: partial
277277
// cxx98-11-error@-1 {{variable templates are a C++14 extension}}
278278
// cxx98-14-error@-2 {{inline variables are a C++17 extension}}
279279
template<> static inline int v2<T>; // #cwg727-v2-T
280-
// cxx98-14-error@-1 {{inline variables are a C++17 extension}}
280+
// cxx98-14-error@-1 {{inline variables are a C++17 extension}}
281281
template<> static inline int v2<U>;
282282
// cxx98-14-error@-1 {{inline variables are a C++17 extension}}
283283
// expected-error@-2 {{duplicate member 'v2'}}

clang/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify %s
2-
template<class T1>
2+
template<class T1>
33
class A {
44
template<class T2> class B {
55
void mf();
66
};
77
};
88

9-
template<> template<> class A<int>::B<double>;
9+
template<> template<> class A<int>::B<double>;
1010
template<> template<> void A<char>::B<char>::mf();
1111

1212
template<> void A<char>::B<int>::mf(); // expected-error{{requires 'template<>'}}
@@ -17,15 +17,15 @@ namespace test1 {
1717
static int bar;
1818
};
1919
typedef A<int> AA;
20-
21-
template <> int AA::foo = 0;
20+
21+
template <> int AA::foo = 0;
2222
int AA::bar = 1; // expected-error {{template specialization requires 'template<>'}}
2323
int A<float>::bar = 2; // expected-error {{template specialization requires 'template<>'}}
2424

25-
template <> class A<double> {
25+
template <> class A<double> {
2626
public:
2727
static int foo;
28-
static int bar;
28+
static int bar;
2929
};
3030

3131
typedef A<double> AB;

0 commit comments

Comments
 (0)