isEvaluatable() implies a constant context.

Assume that we're in a constant context if we're asking if the expression can
be compiled into a constant initializer. This fixes the issue where a
__builtin_constant_p() in a compound literal was diagnosed as not being
constant, even though it's always possible to convert the builtin into a
constant.

llvm-svn: 347512
This commit is contained in:
Bill Wendling 2018-11-24 10:45:55 +00:00
parent 7459398a43
commit 1af8dd6a1e
5 changed files with 17 additions and 5 deletions

View File

@ -583,7 +583,8 @@ public:
/// this function returns true, it returns the folded constant in Result. If /// this function returns true, it returns the folded constant in Result. If
/// the expression is a glvalue, an lvalue-to-rvalue conversion will be /// the expression is a glvalue, an lvalue-to-rvalue conversion will be
/// applied. /// applied.
bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const; bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx,
bool InConstantContext = false) const;
/// EvaluateAsBooleanCondition - Return true if this is a constant /// EvaluateAsBooleanCondition - Return true if this is a constant
/// which we can fold and convert to a boolean condition using /// which we can fold and convert to a boolean condition using

View File

@ -10807,8 +10807,10 @@ static bool EvaluateAsInt(const Expr *E, Expr::EvalResult &ExprResult,
/// we want to. If this function returns true, it returns the folded constant /// we want to. If this function returns true, it returns the folded constant
/// in Result. If this expression is a glvalue, an lvalue-to-rvalue conversion /// in Result. If this expression is a glvalue, an lvalue-to-rvalue conversion
/// will be applied to the result. /// will be applied to the result.
bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const { bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx,
bool InConstantContext) const {
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
Info.InConstantContext = InConstantContext;
return ::EvaluateAsRValue(this, Result, Ctx, Info); return ::EvaluateAsRValue(this, Result, Ctx, Info);
} }
@ -10909,7 +10911,7 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
/// constant folded, but discard the result. /// constant folded, but discard the result.
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, /* in constant context */ true) &&
!hasUnacceptableSideEffect(Result, SEK); !hasUnacceptableSideEffect(Result, SEK);
} }

View File

@ -5798,7 +5798,12 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
: VK_LValue; : VK_LValue;
if (isFileScope) if (isFileScope)
LiteralExpr = ConstantExpr::Create(Context, LiteralExpr); if (auto ILE = dyn_cast<InitListExpr>(LiteralExpr))
for (unsigned i = 0, j = ILE->getNumInits(); i != j; i++) {
Expr *Init = ILE->getInit(i);
ILE->setInit(i, ConstantExpr::Create(Context, Init));
}
Expr *E = new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, Expr *E = new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
VK, LiteralExpr, isFileScope); VK, LiteralExpr, isFileScope);
if (isFileScope) { if (isFileScope) {

View File

@ -10,6 +10,9 @@ inline int bcp(int x) {
struct foo { int x, y; }; struct foo { int x, y; };
int y;
struct foo f = (struct foo){ __builtin_constant_p(y), 42 };
struct foo test0(int expr) { struct foo test0(int expr) {
// CHECK: define i64 @test0(i32 %expr) // CHECK: define i64 @test0(i32 %expr)
// CHECK: call i1 @llvm.is.constant.i32(i32 %expr) // CHECK: call i1 @llvm.is.constant.i32(i32 %expr)

View File

@ -37,9 +37,10 @@ namespace brace_initializers {
POD p = (POD){1, 2}; POD p = (POD){1, 2};
// CHECK-NOT: CXXBindTemporaryExpr {{.*}} 'brace_initializers::POD' // CHECK-NOT: CXXBindTemporaryExpr {{.*}} 'brace_initializers::POD'
// CHECK: CompoundLiteralExpr {{.*}} 'brace_initializers::POD' // CHECK: CompoundLiteralExpr {{.*}} 'brace_initializers::POD'
// CHECK-NEXT: ConstantExpr {{.*}} 'brace_initializers::POD'
// CHECK-NEXT: InitListExpr {{.*}} 'brace_initializers::POD' // CHECK-NEXT: InitListExpr {{.*}} 'brace_initializers::POD'
// CHECK-NEXT: ConstantExpr {{.*}}
// CHECK-NEXT: IntegerLiteral {{.*}} 1{{$}} // CHECK-NEXT: IntegerLiteral {{.*}} 1{{$}}
// CHECK-NEXT: ConstantExpr {{.*}}
// CHECK-NEXT: IntegerLiteral {{.*}} 2{{$}} // CHECK-NEXT: IntegerLiteral {{.*}} 2{{$}}
void test() { void test() {