From 3a91abf311dcc399944882004f3e0b29489d31c7 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 24 Aug 2010 05:27:49 +0000 Subject: [PATCH] Diagnose the presence of multiple initializations of static data members, from Faisal Vali! Fixes PR6904. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111900 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaDecl.cpp | 21 ++++++++++++++++ lib/Sema/SemaDeclCXX.cpp | 19 ++++++++++++++ .../class.static/class.static.data/p4.cpp | 25 +++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 test/CXX/class/class.static/class.static.data/p4.cpp diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index b2c31916b7..0ed93910c7 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4077,6 +4077,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { return; } + + // A definition must end up with a complete type, which means it must be // complete with the restriction that an array type might be completed by the // initializer; note that later code assumes this restriction. @@ -4103,6 +4105,25 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { VDecl->setInvalidDecl(); return; } + + // C++ [class.static.data]p4 + // If a static data member is of const integral or const + // enumeration type, its declaration in the class definition can + // specify a constant-initializer which shall be an integral + // constant expression (5.19). In that case, the member can appear + // in integral constant expressions. The member shall still be + // defined in a namespace scope if it is used in the program and the + // namespace scope definition shall not contain an initializer. + // + // We already performed a redefinition check above, but for static + // data members we also need to check whether there was an in-class + // declaration with an initializer. + const VarDecl* PrevInit = 0; + if (VDecl->isStaticDataMember() && VDecl->getAnyInitializer(PrevInit)) { + Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName(); + Diag(PrevInit->getLocation(), diag::note_previous_definition); + return; + } if (getLangOptions().CPlusPlus && VDecl->hasLocalStorage()) setFunctionHasBranchProtectedScope(); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 9479fac085..d590a3c0e5 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5533,6 +5533,25 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, return; } + // C++ [class.static.data]p4 + // If a static data member is of const integral or const + // enumeration type, its declaration in the class definition can + // specify a constant-initializer which shall be an integral + // constant expression (5.19). In that case, the member can appear + // in integral constant expressions. The member shall still be + // defined in a namespace scope if it is used in the program and the + // namespace scope definition shall not contain an initializer. + // + // We already performed a redefinition check above, but for static + // data members we also need to check whether there was an in-class + // declaration with an initializer. + const VarDecl* PrevInit = 0; + if (VDecl->isStaticDataMember() && VDecl->getAnyInitializer(PrevInit)) { + Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName(); + Diag(PrevInit->getLocation(), diag::note_previous_definition); + return; + } + // If either the declaration has a dependent type or if any of the // expressions is type-dependent, we represent the initialization // via a ParenListExpr for later use during template instantiation. diff --git a/test/CXX/class/class.static/class.static.data/p4.cpp b/test/CXX/class/class.static/class.static.data/p4.cpp new file mode 100644 index 0000000000..2b1eca7419 --- /dev/null +++ b/test/CXX/class/class.static/class.static.data/p4.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +struct InClassInitializerOnly { + static const int i = 0; +}; +int const InClassInitializerOnly::i; + +struct OutOfClassInitializerOnly { + static const int i; +}; +int const OutOfClassInitializerOnly::i = 0; + +struct InClassInitializerAndOutOfClassCopyInitializer { + static const int i = 0; // expected-note{{previous definition is here}} +}; +int const InClassInitializerAndOutOfClassCopyInitializer::i = 0; // expected-error{{redefinition of 'i'}} + +struct InClassInitializerAndOutOfClassDirectInitializer { + static const int i = 0; // expected-note{{previous definition is here}} +}; +int const InClassInitializerAndOutOfClassDirectInitializer::i(0); // expected-error{{redefinition of 'i'}} + + + +int main() { } + -- 2.40.0