The standard doesn't allow this, but mutable constexpr variables break the
semantics so badly that we can't reasonably accept them.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141768
91177308-0d34-0410-b5e6-
96231b3b80d8
"%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">;
// Objective-C++
def err_objc_decls_may_only_appear_in_global_scope : Error<
}
// Record if this field is the first non-literal field or base.
- if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType())
+ // 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())
data().HasNonLiteralTypeFieldsOrBases = true;
if (Field->hasInClassInitializer()) {
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()) {
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() {
+ // FIXME: correctly check whether the initializer is a constant expression.
+ constexpr MM m = { 0 }; // desired-error {{must be a constant expression}}
+ ++m.n;
+ return Id<m.n>().k; // expected-error {{not an integral constant expression}}
+ }
+}