CWG issue 1405: mutable members are allowed in literal types, but can't undergo
lvalue-to-rvalue conversions in constant expressions.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150145 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index d522103..aa24e9b 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -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()) {
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 48e0c6f..e43884e 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -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()) {
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 82f7fed..3d32091 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -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);
+          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;
+            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.
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index daf0b68..9fd611b 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -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()) {