[cfe-commits] r150145 - in /cfe/trunk: include/clang/Basic/DiagnosticASTKinds.td include/clang/Basic/DiagnosticSemaKinds.td lib/AST/DeclCXX.cpp lib/AST/ExprConstant.cpp lib/CodeGen/CGDecl.cpp lib/Sema/SemaType.cpp test/CXX/basic/basic.types/p10.cpp test/SemaCXX/constant-expression-cxx11.cpp

Richard Smith richard-llvm at metafoo.co.uk
Wed Feb 8 19:29:58 PST 2012


Author: rsmith
Date: Wed Feb  8 21:29:58 2012
New Revision: 150145

URL: http://llvm.org/viewvc/llvm-project?rev=150145&view=rev
Log:
CWG issue 1405: mutable members are allowed in literal types, but can't undergo
lvalue-to-rvalue conversions in constant expressions.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/CodeGen/CGDecl.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/CXX/basic/basic.types/p10.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=150145&r1=150144&r2=150145&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Wed Feb  8 21:29:58 2012
@@ -85,6 +85,8 @@
 def note_constexpr_ltor_volatile_obj : Note<
   "read of volatile %select{temporary|object %1|member %1}0 is not allowed in "
   "a constant expression">;
+def note_constexpr_ltor_mutable : Note<
+  "read of mutable member %0 is not allowed in a constant expression">;
 def note_constexpr_ltor_non_const_int : Note<
   "read of non-const variable %0 is not allowed in a constant expression">;
 def note_constexpr_ltor_non_constexpr : Note<

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=150145&r1=150144&r2=150145&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Feb  8 21:29:58 2012
@@ -1425,8 +1425,6 @@
   "%0 is not literal because it has a user-provided destructor">;
 def note_non_literal_nontrivial_dtor : Note<
   "%0 is not literal because it has a non-trivial destructor">;
-def note_non_literal_mutable_field : Note<
-  "%0 is not literal because it has a mutable data member">;
 
 // C++11 char16_t/char32_t
 def warn_cxx98_compat_unicode_type : Warning<

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=150145&r1=150144&r2=150145&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Feb  8 21:29:58 2012
@@ -800,11 +800,7 @@
     }
 
     // Record if this field is the first non-literal field or base.
-    // As a slight variation on the standard, we regard mutable members as being
-    // non-literal, since mutating a constexpr variable would break C++11
-    // constant expression semantics.
-    if ((!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType()) ||
-        Field->isMutable())
+    if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType())
       data().HasNonLiteralTypeFieldsOrBases = true;
 
     if (Field->hasInClassInitializer()) {

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=150145&r1=150144&r2=150145&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Wed Feb  8 21:29:58 2012
@@ -1453,6 +1453,13 @@
         O = &O->getArrayFiller();
       ObjType = CAT->getElementType();
     } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) {
+      if (Field->isMutable()) {
+        Info.Diag(E->getExprLoc(), diag::note_constexpr_ltor_mutable, 1)
+          << Field;
+        Info.Note(Field->getLocation(), diag::note_declared_at);
+        return false;
+      }
+
       // Next subobject is a class, struct or union field.
       RecordDecl *RD = ObjType->castAs<RecordType>()->getDecl();
       if (RD->isUnion()) {

Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=150145&r1=150144&r2=150145&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Wed Feb  8 21:29:58 2012
@@ -773,11 +773,15 @@
         // emit it as a global instead.
         if (CGM.getCodeGenOpts().MergeAllConstants && Ty.isConstQualified() &&
             !NRVO && !isByRef && Ty->isLiteralType()) {
-          EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
-
-          emission.Address = 0; // signal this condition to later callbacks
-          assert(emission.wasEmittedAsGlobal());
-          return emission;
+          CXXRecordDecl *RD =
+            Ty->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+          if (!RD || !RD->hasMutableFields()) {
+            EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
+
+            emission.Address = 0; // signal this condition to later callbacks
+            assert(emission.wasEmittedAsGlobal());
+            return emission;
+          }
         }
 
         // Otherwise, tell the initialization code that we're in this case.

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=150145&r1=150144&r2=150145&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Wed Feb  8 21:29:58 2012
@@ -4302,9 +4302,6 @@
         Diag((*I)->getLocation(), diag::note_non_literal_field)
           << RD << (*I) << (*I)->getType();
         return true;
-      } else if ((*I)->isMutable()) {
-        Diag((*I)->getLocation(), diag::note_non_literal_mutable_field) << RD;
-        return true;
       }
     }
   } else if (!RD->hasTrivialDestructor()) {

Modified: cfe/trunk/test/CXX/basic/basic.types/p10.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.types/p10.cpp?rev=150145&r1=150144&r2=150145&view=diff
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.types/p10.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.types/p10.cpp Wed Feb  8 21:29:58 2012
@@ -107,21 +107,3 @@
   S s[3]; // expected-note {{data member 's' of non-literal type 'S [3]'}}
 };
 constexpr int f(ArrBad); // expected-error {{1st parameter type 'ArrBad' is not a literal type}}
-
-
-// As a non-conforming tweak to the standard, we do not allow a literal type to
-// have any mutable data members.
-namespace MutableMembers {
-  struct MM {
-    mutable int n; // expected-note {{'MM' is not literal because it has a mutable data member}}
-  };
-  constexpr int f(MM); // expected-error {{not a literal type}}
-
-  // Here's one reason why allowing this would be a disaster...
-  template<int n> struct Id { int k = n; };
-  int f() {
-    constexpr MM m = { 0 }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-literal type 'const MutableMembers::MM' cannot be used in a constant expression}} expected-note {{here}}
-    ++m.n;
-    return Id<m.n>().k; // expected-error {{not a constant expression}} expected-note {{initializer of 'm' is not a constant expression}}
-  }
-}

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=150145&r1=150144&r2=150145&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Wed Feb  8 21:29:58 2012
@@ -1121,6 +1121,30 @@
   static_assert(s2.f == 7, "");
 }
 
+// DR1405: don't allow reading mutable members in constant expressions.
+namespace MutableMembers {
+  struct MM {
+    mutable int n; // expected-note 3{{declared here}}
+  } constexpr mm = { 4 };
+  constexpr int mmn = mm.n; // expected-error {{constant expression}} expected-note {{read of mutable member 'n' is not allowed in a constant expression}}
+  int x = (mm.n = 1, 3);
+  constexpr int mmn2 = mm.n; // expected-error {{constant expression}} expected-note {{read of mutable member 'n' is not allowed in a constant expression}}
+
+  // Here's one reason why allowing this would be a disaster...
+  template<int n> struct Id { int k = n; };
+  int f() {
+    constexpr MM m = { 0 };
+    ++m.n;
+    return Id<m.n>().k; // expected-error {{not a constant expression}} expected-note {{read of mutable member 'n' is not allowed in a constant expression}}
+  }
+
+  struct A { int n; };
+  struct B { mutable A a; }; // expected-note {{here}}
+  struct C { B b; };
+  constexpr C c[3] = {};
+  constexpr int k = c[1].b.a.n; // expected-error {{constant expression}} expected-note {{mutable}}
+}
+
 namespace Fold {
 
   // This macro forces its argument to be constant-folded, even if it's not





More information about the cfe-commits mailing list