aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--lib/AST/DeclCXX.cpp6
-rw-r--r--lib/AST/ExprConstant.cpp7
-rw-r--r--lib/CodeGen/CGDecl.cpp14
-rw-r--r--lib/Sema/SemaType.cpp3
-rw-r--r--test/CXX/basic/basic.types/p10.cpp18
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp24
8 files changed, 43 insertions, 33 deletions
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index 978df36f9f..80d9329172 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -85,6 +85,8 @@ def note_constexpr_ltor_volatile_type : Note<
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<
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index c5155c6e13..cbb4d177ef 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1425,8 +1425,6 @@ def note_non_literal_user_provided_dtor : Note<
"%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<
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index d5221031a5..aa24e9b625 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -800,11 +800,7 @@ NotASpecialMember:;
}
// 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 48e0c6f7da..e43884e376 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -1453,6 +1453,13 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
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 82f7fed7ba..3d32091a4b 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -773,11 +773,15 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
// 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.
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index daf0b683b6..9fd611b5fe 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -4302,9 +4302,6 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
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()) {
diff --git a/test/CXX/basic/basic.types/p10.cpp b/test/CXX/basic/basic.types/p10.cpp
index 11c2f5fc49..def4dc95bb 100644
--- a/test/CXX/basic/basic.types/p10.cpp
+++ b/test/CXX/basic/basic.types/p10.cpp
@@ -107,21 +107,3 @@ struct ArrBad {
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}}
- }
-}
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index ccbc8c1abd..58f36fdf9c 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1121,6 +1121,30 @@ namespace IndirectField {
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