mirror of https://github.com/microsoft/clang.git
Revert r332847; it caused us to miscompile certain forms of reference initialization.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@332886 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
c3d5cc8d43
commit
1bc857476c
|
@ -537,13 +537,6 @@ public:
|
||||||
bool isConstantInitializer(ASTContext &Ctx, bool ForRef,
|
bool isConstantInitializer(ASTContext &Ctx, bool ForRef,
|
||||||
const Expr **Culprit = nullptr) const;
|
const Expr **Culprit = nullptr) const;
|
||||||
|
|
||||||
enum SideEffectsKind {
|
|
||||||
SE_NoSideEffects, ///< Strictly evaluate the expression.
|
|
||||||
SE_AllowUndefinedBehavior, ///< Allow UB that we can give a value, but not
|
|
||||||
///< arbitrary unmodeled side effects.
|
|
||||||
SE_AllowSideEffects ///< Allow any unmodeled side effect.
|
|
||||||
};
|
|
||||||
|
|
||||||
/// EvalStatus is a struct with detailed info about an evaluation in progress.
|
/// EvalStatus is a struct with detailed info about an evaluation in progress.
|
||||||
struct EvalStatus {
|
struct EvalStatus {
|
||||||
/// Whether the evaluated expression has side effects.
|
/// Whether the evaluated expression has side effects.
|
||||||
|
@ -572,11 +565,6 @@ public:
|
||||||
bool hasSideEffects() const {
|
bool hasSideEffects() const {
|
||||||
return HasSideEffects;
|
return HasSideEffects;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasUnacceptableSideEffect(SideEffectsKind SEK) {
|
|
||||||
return (SEK < SE_AllowSideEffects && HasSideEffects) ||
|
|
||||||
(SEK < SE_AllowUndefinedBehavior && HasUndefinedBehavior);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// EvalResult is a struct with detailed info about an evaluated expression.
|
/// EvalResult is a struct with detailed info about an evaluated expression.
|
||||||
|
@ -603,6 +591,13 @@ public:
|
||||||
/// side-effects.
|
/// side-effects.
|
||||||
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const;
|
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const;
|
||||||
|
|
||||||
|
enum SideEffectsKind {
|
||||||
|
SE_NoSideEffects, ///< Strictly evaluate the expression.
|
||||||
|
SE_AllowUndefinedBehavior, ///< Allow UB that we can give a value, but not
|
||||||
|
///< arbitrary unmodeled side effects.
|
||||||
|
SE_AllowSideEffects ///< Allow any unmodeled side effect.
|
||||||
|
};
|
||||||
|
|
||||||
/// EvaluateAsInt - Return true if this is a constant which we can fold and
|
/// EvaluateAsInt - Return true if this is a constant which we can fold and
|
||||||
/// convert to an integer, using any crazy technique that we want to.
|
/// convert to an integer, using any crazy technique that we want to.
|
||||||
bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx,
|
bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx,
|
||||||
|
|
|
@ -10312,6 +10312,12 @@ bool Expr::EvaluateAsBooleanCondition(bool &Result,
|
||||||
HandleConversionToBool(Scratch.Val, Result);
|
HandleConversionToBool(Scratch.Val, Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool hasUnacceptableSideEffect(Expr::EvalStatus &Result,
|
||||||
|
Expr::SideEffectsKind SEK) {
|
||||||
|
return (SEK < Expr::SE_AllowSideEffects && Result.HasSideEffects) ||
|
||||||
|
(SEK < Expr::SE_AllowUndefinedBehavior && Result.HasUndefinedBehavior);
|
||||||
|
}
|
||||||
|
|
||||||
bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx,
|
bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx,
|
||||||
SideEffectsKind AllowSideEffects) const {
|
SideEffectsKind AllowSideEffects) const {
|
||||||
if (!getType()->isIntegralOrEnumerationType())
|
if (!getType()->isIntegralOrEnumerationType())
|
||||||
|
@ -10319,7 +10325,7 @@ bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx,
|
||||||
|
|
||||||
EvalResult ExprResult;
|
EvalResult ExprResult;
|
||||||
if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isInt() ||
|
if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isInt() ||
|
||||||
ExprResult.hasUnacceptableSideEffect(AllowSideEffects))
|
hasUnacceptableSideEffect(ExprResult, AllowSideEffects))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Result = ExprResult.Val.getInt();
|
Result = ExprResult.Val.getInt();
|
||||||
|
@ -10333,7 +10339,7 @@ bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx,
|
||||||
|
|
||||||
EvalResult ExprResult;
|
EvalResult ExprResult;
|
||||||
if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isFloat() ||
|
if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isFloat() ||
|
||||||
ExprResult.hasUnacceptableSideEffect(AllowSideEffects))
|
hasUnacceptableSideEffect(ExprResult, AllowSideEffects))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Result = ExprResult.Val.getFloat();
|
Result = ExprResult.Val.getFloat();
|
||||||
|
@ -10411,7 +10417,7 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
|
||||||
bool Expr::isEvaluatable(const ASTContext &Ctx, SideEffectsKind SEK) const {
|
bool Expr::isEvaluatable(const ASTContext &Ctx, SideEffectsKind SEK) const {
|
||||||
EvalResult Result;
|
EvalResult Result;
|
||||||
return EvaluateAsRValue(Result, Ctx) &&
|
return EvaluateAsRValue(Result, Ctx) &&
|
||||||
!Result.hasUnacceptableSideEffect(SEK);
|
!hasUnacceptableSideEffect(Result, SEK);
|
||||||
}
|
}
|
||||||
|
|
||||||
APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
|
APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
|
||||||
|
|
|
@ -1392,40 +1392,20 @@ static QualType getNonMemoryType(CodeGenModule &CGM, QualType type) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the specified initializer is equivalent to zero initialization.
|
|
||||||
static bool isZeroInitializer(ConstantEmitter &CE, const Expr *Init) {
|
|
||||||
if (auto *E = dyn_cast_or_null<CXXConstructExpr>(Init)) {
|
|
||||||
CXXConstructorDecl *CD = E->getConstructor();
|
|
||||||
return CD->isDefaultConstructor() && CD->isTrivial();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto *IL = dyn_cast_or_null<InitListExpr>(Init)) {
|
|
||||||
for (auto I : IL->inits())
|
|
||||||
if (!isZeroInitializer(CE, I))
|
|
||||||
return false;
|
|
||||||
if (const Expr *Filler = IL->getArrayFiller())
|
|
||||||
return isZeroInitializer(CE, Filler);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QualType InitTy = Init->getType();
|
|
||||||
if (InitTy->isIntegralOrEnumerationType() || InitTy->isPointerType()) {
|
|
||||||
Expr::EvalResult Result;
|
|
||||||
if (Init->EvaluateAsRValue(Result, CE.CGM.getContext()) &&
|
|
||||||
!Result.hasUnacceptableSideEffect(Expr::SE_NoSideEffects))
|
|
||||||
return (Result.Val.isInt() && Result.Val.getInt().isNullValue()) ||
|
|
||||||
(Result.Val.isLValue() && Result.Val.isNullPointer());
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) {
|
llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) {
|
||||||
// Make a quick check if variable can be default NULL initialized
|
// Make a quick check if variable can be default NULL initialized
|
||||||
// and avoid going through rest of code which may do, for c++11,
|
// and avoid going through rest of code which may do, for c++11,
|
||||||
// initialization of memory to all NULLs.
|
// initialization of memory to all NULLs.
|
||||||
if (!D.hasLocalStorage() && isZeroInitializer(*this, D.getInit()))
|
if (!D.hasLocalStorage()) {
|
||||||
|
QualType Ty = CGM.getContext().getBaseElementType(D.getType());
|
||||||
|
if (Ty->isRecordType())
|
||||||
|
if (const CXXConstructExpr *E =
|
||||||
|
dyn_cast_or_null<CXXConstructExpr>(D.getInit())) {
|
||||||
|
const CXXConstructorDecl *CD = E->getConstructor();
|
||||||
|
if (CD->isTrivial() && CD->isDefaultConstructor())
|
||||||
return CGM.EmitNullConstant(D.getType());
|
return CGM.EmitNullConstant(D.getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QualType destType = D.getType();
|
QualType destType = D.getType();
|
||||||
|
|
||||||
|
|
|
@ -167,7 +167,7 @@ void g30() {
|
||||||
int : 1;
|
int : 1;
|
||||||
int x;
|
int x;
|
||||||
} a = {};
|
} a = {};
|
||||||
// CHECK: @g30.a = internal global %struct.anon.1 zeroinitializer, align 1
|
// CHECK: @g30.a = internal global %struct.anon.1 <{ i8 undef, i32 0 }>, align 1
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ struct foo {
|
||||||
// CHECK: @u = global %union.anon zeroinitializer
|
// CHECK: @u = global %union.anon zeroinitializer
|
||||||
union { int i; float f; } u = { };
|
union { int i; float f; } u = { };
|
||||||
|
|
||||||
// CHECK: @u2 = global %union.anon.0 zeroinitializer
|
// CHECK: @u2 = global { i32, [4 x i8] } { i32 0, [4 x i8] undef }
|
||||||
union { int i; double f; } u2 = { };
|
union { int i; double f; } u2 = { };
|
||||||
|
|
||||||
// CHECK: @u3 = global %union.anon.1 zeroinitializer
|
// CHECK: @u3 = global %union.anon.1 zeroinitializer
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
union x {long long b;union x* a;} r = {.a = &r};
|
union x {long long b;union x* a;} r = {.a = &r};
|
||||||
|
|
||||||
|
|
||||||
// CHECK: global %union.z zeroinitializer
|
// CHECK: global { [3 x i8], [5 x i8] } { [3 x i8] zeroinitializer, [5 x i8] undef }
|
||||||
union z {
|
union z {
|
||||||
char a[3];
|
char a[3];
|
||||||
long long b;
|
long long b;
|
||||||
|
|
|
@ -51,30 +51,3 @@ namespace NonTrivialInit {
|
||||||
// meaningful.
|
// meaningful.
|
||||||
B b[30] = {};
|
B b[30] = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ZeroInit {
|
|
||||||
enum { Zero, One };
|
|
||||||
constexpr int zero() { return 0; }
|
|
||||||
constexpr int *null() { return nullptr; }
|
|
||||||
struct Filler {
|
|
||||||
int x;
|
|
||||||
Filler();
|
|
||||||
};
|
|
||||||
struct S1 {
|
|
||||||
int x;
|
|
||||||
};
|
|
||||||
|
|
||||||
// These declarations, if implemented elementwise, require huge
|
|
||||||
// amout of memory and compiler time.
|
|
||||||
unsigned char data_1[1024 * 1024 * 1024 * 2u] = { 0 };
|
|
||||||
unsigned char data_2[1024 * 1024 * 1024 * 2u] = { Zero };
|
|
||||||
unsigned char data_3[1024][1024][1024] = {{{0}}};
|
|
||||||
unsigned char data_4[1024 * 1024 * 1024 * 2u] = { zero() };
|
|
||||||
int *data_5[1024 * 1024 * 512] = { nullptr };
|
|
||||||
int *data_6[1024 * 1024 * 512] = { null() };
|
|
||||||
struct S1 data_7[1024 * 1024 * 512] = {{0}};
|
|
||||||
|
|
||||||
// This variable must be initialized elementwise.
|
|
||||||
Filler data_e1[1024] = {};
|
|
||||||
// CHECK: getelementptr inbounds {{.*}} @_ZN8ZeroInit7data_e1E
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,14 +17,14 @@ namespace Constant {
|
||||||
|
|
||||||
C c1 = {};
|
C c1 = {};
|
||||||
C c2 = {1};
|
C c2 = {1};
|
||||||
// CHECK: @_ZN8Constant2c1E = global %"struct.Constant::C" zeroinitializer, align 1
|
// CHECK: @_ZN8Constant2c1E = global { i8 } zeroinitializer, align 1
|
||||||
// CHECK: @_ZN8Constant2c2E = global { i8 } { i8 1 }, align 1
|
// CHECK: @_ZN8Constant2c2E = global { i8 } { i8 1 }, align 1
|
||||||
|
|
||||||
// Test packing bases into tail padding.
|
// Test packing bases into tail padding.
|
||||||
D d1 = {};
|
D d1 = {};
|
||||||
D d2 = {1, 2, 3};
|
D d2 = {1, 2, 3};
|
||||||
D d3 = {1};
|
D d3 = {1};
|
||||||
// CHECK: @_ZN8Constant2d1E = global %"struct.Constant::D" zeroinitializer, align 4
|
// CHECK: @_ZN8Constant2d1E = global { i32, i8, i8 } zeroinitializer, align 4
|
||||||
// CHECK: @_ZN8Constant2d2E = global { i32, i8, i8 } { i32 1, i8 2, i8 3 }, align 4
|
// CHECK: @_ZN8Constant2d2E = global { i32, i8, i8 } { i32 1, i8 2, i8 3 }, align 4
|
||||||
// CHECK: @_ZN8Constant2d3E = global { i32, i8, i8 } { i32 1, i8 0, i8 0 }, align 4
|
// CHECK: @_ZN8Constant2d3E = global { i32, i8, i8 } { i32 1, i8 0, i8 0 }, align 4
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,12 @@
|
||||||
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm %s -o - -std=c++11 | FileCheck %s --check-prefix=CHECK-CXX11
|
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm %s -o - -std=c++11 | FileCheck %s --check-prefix=CHECK-CXX11
|
||||||
// expected-no-diagnostics
|
// expected-no-diagnostics
|
||||||
|
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
// CHECK-CXX11: @_ZZ15InitRefWithListvE1r = internal constant i32* @_ZGRZ15InitRefWithListvE1r_
|
||||||
|
// CHECK-CXX11: @_ZGRZ15InitRefWithListvE1r_ = internal constant i32 123
|
||||||
|
int InitRefWithList() { static const int &r = {123}; return r; }
|
||||||
|
#endif
|
||||||
|
|
||||||
struct XPTParamDescriptor {};
|
struct XPTParamDescriptor {};
|
||||||
struct nsXPTParamInfo {
|
struct nsXPTParamInfo {
|
||||||
nsXPTParamInfo(const XPTParamDescriptor& desc);
|
nsXPTParamInfo(const XPTParamDescriptor& desc);
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
// RUN: %clang_cc1 -S -o %t.ll -mllvm -debug-only=exprconstant %s 2>&1 | \
|
||||||
|
// RUN: FileCheck %s
|
||||||
|
// REQUIRES: asserts
|
||||||
|
|
||||||
|
struct S { int i; };
|
||||||
|
|
||||||
|
static struct S arr[100000000] = {{ 0 }};
|
||||||
|
// CHECK: The number of elements to initialize: 1.
|
||||||
|
|
||||||
|
struct S *foo() { return arr; }
|
Loading…
Reference in New Issue