зеркало из https://github.com/microsoft/clang-1.git
Fix wrong-code bug when a const automatic variable of struct type has both a
mutable member and a constant initializer. We'd previously promoted such variables to global constants, resulting in nasal demons if the mutable member was modified. This is only a temporary fix. The subtle interplay between isConstantInitializer and CGExprConstant is very bug-prone; there are some other issues in this area which I will be addressing in subsequent, more major reworking of this code. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145654 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
b87699353a
Коммит
4bb6686274
|
@ -739,11 +739,13 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
|
|||
D.isNRVOVariable();
|
||||
|
||||
// If this value is a POD array or struct with a statically
|
||||
// determinable constant initializer, there are optimizations we
|
||||
// can do.
|
||||
// TODO: we can potentially constant-evaluate non-POD structs and
|
||||
// arrays as long as the initialization is trivial (e.g. if they
|
||||
// have a non-trivial destructor, but not a non-trivial constructor).
|
||||
// determinable constant initializer, there are optimizations we can do.
|
||||
//
|
||||
// TODO: we should constant-evaluate any variable of literal type
|
||||
// as long as it is initialized by a constant expression. Currently,
|
||||
// isConstantInitializer produces wrong answers for structs with
|
||||
// reference or bitfield members, and a few other cases, and checking
|
||||
// for POD-ness protects us from some of these.
|
||||
if (D.getInit() &&
|
||||
(Ty->isArrayType() || Ty->isRecordType()) &&
|
||||
(Ty.isPODType(getContext()) ||
|
||||
|
@ -751,9 +753,10 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
|
|||
D.getInit()->isConstantInitializer(getContext(), false)) {
|
||||
|
||||
// If the variable's a const type, and it's neither an NRVO
|
||||
// candidate nor a __block variable, emit it as a global instead.
|
||||
// candidate nor a __block variable and has no mutable members,
|
||||
// emit it as a global instead.
|
||||
if (CGM.getCodeGenOpts().MergeAllConstants && Ty.isConstQualified() &&
|
||||
!NRVO && !isByRef) {
|
||||
!NRVO && !isByRef && Ty->isLiteralType()) {
|
||||
EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
|
||||
|
||||
emission.Address = 0; // signal this condition to later callbacks
|
||||
|
|
|
@ -45,3 +45,14 @@ namespace test2 {
|
|||
// We don't expect to fold this in the frontend, but make sure it doesn't crash.
|
||||
// CHECK: @PR9558 = global float 0.000000e+0
|
||||
float PR9558 = reinterpret_cast<const float&>("asd");
|
||||
|
||||
// An initialized const automatic variable cannot be promoted to a constant
|
||||
// global if it has a mutable member.
|
||||
struct MutableMember {
|
||||
mutable int n;
|
||||
};
|
||||
int writeToMutable() {
|
||||
// CHECK-NOT: {{.*}}MM{{.*}} = {{.*}}constant
|
||||
const MutableMember MM = { 0 };
|
||||
return ++MM.n;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче