[cfe-commits] r113663 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaDecl.cpp test/SemaCXX/class.cpp test/SemaTemplate/instantiate-static-var.cpp

John McCall rjmccall at apple.com
Fri Sep 10 16:21:23 PDT 2010


Author: rjmccall
Date: Fri Sep 10 18:21:22 2010
New Revision: 113663

URL: http://llvm.org/viewvc/llvm-project?rev=113663&view=rev
Log:
Support in-class initialization of static const floating-point data members.


Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/SemaCXX/class.cpp
    cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=113663&r1=113662&r2=113663&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Sep 10 18:21:22 2010
@@ -619,7 +619,7 @@
 def err_not_integral_type_anon_bitfield : Error<
   "anonymous bit-field has non-integral type %0">;
 def err_member_initialization : Error<
-  "%0 can only be initialized if it is a static const integral data member">;
+  "fields can only be initialized in constructors">;
 def err_member_function_initialization : Error<
   "initializer on function does not look like a pure-specifier">;
 def err_non_virtual_pure : Error<
@@ -2826,10 +2826,15 @@
 def err_not_direct_base_or_virtual : Error<
   "type %0 is not a direct or virtual base of %1">;
 
-def err_in_class_initializer_non_integral_type : Error<
-  "in-class initializer has non-integral, non-enumeration type %0">;
+def err_in_class_initializer_non_const : Error<
+  "non-const static data member must be initialized out of line">;
+def err_in_class_initializer_bad_type : Error<
+  "static data member of type %0 must be initialized out of line">;
+def ext_in_class_initializer_float_type : ExtWarn<
+  "in-class initializer for static data member of type %0 "
+  "is a C++0x extension">;
 def err_in_class_initializer_non_constant : Error<
-  "in-class initializer is not an integral constant expression">;
+  "in-class initializer is not a constant expression">;
 
 // C++ anonymous unions and GNU anonymous structs/unions
 def ext_anonymous_union : Extension<

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=113663&r1=113662&r2=113663&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Sep 10 18:21:22 2010
@@ -4115,8 +4115,7 @@
     if (getLangOptions().CPlusPlus &&
         RealDecl->getLexicalDeclContext()->isRecord() &&
         isa<NamedDecl>(RealDecl))
-      Diag(RealDecl->getLocation(), diag::err_member_initialization)
-        << cast<NamedDecl>(RealDecl)->getDeclName();
+      Diag(RealDecl->getLocation(), diag::err_member_initialization);
     else
       Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
     RealDecl->setInvalidDecl();
@@ -4220,34 +4219,38 @@
     //   static const int value = 17;
     // };
 
-    // Attach the initializer
-    VDecl->setInit(Init);
+    // Try to perform the initialization regardless.
+    if (!VDecl->isInvalidDecl()) {
+      InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1);
+      ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
+                                          MultiExprArg(*this, &Init, 1),
+                                          &DclT);
+      if (Result.isInvalid()) {
+        VDecl->setInvalidDecl();
+        return;
+      }
+
+      Init = Result.takeAs<Expr>();
+    }
 
     // C++ [class.mem]p4:
     //   A member-declarator can contain a constant-initializer only
     //   if it declares a static member (9.4) of const integral or
     //   const enumeration type, see 9.4.2.
     QualType T = VDecl->getType();
-    if (!T->isDependentType() &&
-        (!Context.getCanonicalType(T).isConstQualified() ||
-         !T->isIntegralOrEnumerationType())) {
-      Diag(VDecl->getLocation(), diag::err_member_initialization)
-        << VDecl->getDeclName() << Init->getSourceRange();
+
+    // Do nothing on dependent types.
+    if (T->isDependentType()) {
+
+    // Require constness.
+    } else if (!T.isConstQualified()) {
+      Diag(VDecl->getLocation(), diag::err_in_class_initializer_non_const)
+        << Init->getSourceRange();
       VDecl->setInvalidDecl();
-    } else {
-      // 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).
-      if (!Init->isTypeDependent() &&
-          !Init->getType()->isIntegralOrEnumerationType()) {
-        // We have a non-dependent, non-integral or enumeration type.
-        Diag(Init->getSourceRange().getBegin(),
-             diag::err_in_class_initializer_non_integral_type)
-          << Init->getType() << Init->getSourceRange();
-        VDecl->setInvalidDecl();
-      } else if (!Init->isTypeDependent() && !Init->isValueDependent()) {
+
+    // We allow integer constant expressions in all cases.
+    } else if (T->isIntegralOrEnumerationType()) {
+      if (!Init->isValueDependent()) {
         // Check whether the expression is a constant expression.
         llvm::APSInt Value;
         SourceLocation Loc;
@@ -4255,8 +4258,33 @@
           Diag(Loc, diag::err_in_class_initializer_non_constant)
             << Init->getSourceRange();
           VDecl->setInvalidDecl();
-        } else if (!VDecl->getType()->isDependentType())
-          ImpCastExprToType(Init, VDecl->getType(), CK_IntegralCast);
+        }
+      }
+
+    // We allow floating-point constants as an extension in C++03, and
+    // C++0x has far more complicated rules that we don't really
+    // implement fully.
+    } else {
+      bool Allowed = false;
+      if (getLangOptions().CPlusPlus0x) {
+        Allowed = T->isLiteralType();
+      } else if (T->isFloatingType()) { // also permits complex, which is ok
+        Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type)
+          << T << Init->getSourceRange();
+        Allowed = true;
+      }
+
+      if (!Allowed) {
+        Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type)
+          << T << Init->getSourceRange();
+        VDecl->setInvalidDecl();
+
+      // TODO: there are probably expressions that pass here that shouldn't.
+      } else if (!Init->isValueDependent() &&
+                 !Init->isConstantInitializer(Context, false)) {
+        Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant)
+          << Init->getSourceRange();
+        VDecl->setInvalidDecl();
       }
     }
   } else if (VDecl->isFileVarDecl()) {

Modified: cfe/trunk/test/SemaCXX/class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/class.cpp?rev=113663&r1=113662&r2=113663&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/class.cpp (original)
+++ cfe/trunk/test/SemaCXX/class.cpp Fri Sep 10 18:21:22 2010
@@ -12,16 +12,18 @@
   }
 
   class NestedC {
+  public:
+    NestedC(int);
     void m() {
       sx = 0;
-      x = 0; // expected-error {{error: invalid use of nonstatic data member 'x'}}
+      x = 0; // expected-error {{invalid use of nonstatic data member 'x'}}
     }
   };
 
   int b : 1, w : 2;
   int : 1, : 2;
   typedef int E : 1; // expected-error {{typedef member 'E' cannot be a bit-field}}
-  static int sb : 1; // expected-error {{error: static member 'sb' cannot be a bit-field}}
+  static int sb : 1; // expected-error {{static member 'sb' cannot be a bit-field}}
   static int vs;
 
   typedef int func();
@@ -32,10 +34,10 @@
 
   enum E1 { en1, en2 };
 
-  int i = 0; // expected-error {{error: 'i' can only be initialized if it is a static const integral data member}}
-  static int si = 0; // expected-error {{error: 'si' can only be initialized if it is a static const integral data member}}
-  static const NestedC ci = 0; // expected-error {{error: 'ci' can only be initialized if it is a static const integral data member}}
-  static const int nci = vs; // expected-error {{in-class initializer is not an integral constant expression}}
+  int i = 0; // expected-error {{fields can only be initialized in constructors}}
+  static int si = 0; // expected-error {{non-const static data member must be initialized out of line}}
+  static const NestedC ci = 0; // expected-error {{static data member of type 'const C::NestedC' must be initialized out of line}}
+  static const int nci = vs; // expected-error {{in-class initializer is not a constant expression}}
   static const int vi = 0;
   static const E evi = 0;
 
@@ -165,3 +167,12 @@
     C() {}
   } // expected-error{{expected ';' after class}}
 }
+
+namespace rdar8367341 {
+  float foo();
+
+  struct A {
+    static const float x = 5.0f; // expected-warning {{in-class initializer for static data member of type 'const float' is a C++0x extension}}
+    static const float y = foo(); // expected-warning {{in-class initializer for static data member of type 'const float' is a C++0x extension}} expected-error {{in-class initializer is not a constant expression}}
+  };
+}

Modified: cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp?rev=113663&r1=113662&r2=113663&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp Fri Sep 10 18:21:22 2010
@@ -2,7 +2,7 @@
 template<typename T, T Divisor>
 class X {
 public:
-  static const T value = 10 / Divisor; // expected-error{{in-class initializer is not an integral constant expression}}
+  static const T value = 10 / Divisor; // expected-error{{in-class initializer is not a constant expression}}
 };
 
 int array1[X<int, 2>::value == 5? 1 : -1];
@@ -11,7 +11,7 @@
 
 template<typename T>
 class Y {
-  static const T value = 0; // expected-error{{'value' can only be initialized if it is a static const integral data member}}
+  static const T value = 0; // expected-warning{{in-class initializer for static data member of type 'float const' is a C++0x extension}}
 };
 
 Y<float> fy; // expected-note{{in instantiation of template class 'Y<float>' requested here}}





More information about the cfe-commits mailing list