forked from OSchip/llvm-project
Specify constant context in constant emitter
The constant emitter may need to evaluate the expression in a constant context. For exasmple, global initializer lists. llvm-svn: 348070
This commit is contained in:
parent
2d6324c3cb
commit
2a81f6670d
|
@ -8199,6 +8199,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
|
|||
// We can delay calculation of __builtin_constant_p until after
|
||||
// inlining. Note: This diagnostic won't be shown to the user.
|
||||
Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
|
||||
return false;
|
||||
}
|
||||
return Success(false, E);
|
||||
}
|
||||
|
|
|
@ -1455,6 +1455,7 @@ llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) {
|
|||
if (CD->isTrivial() && CD->isDefaultConstructor())
|
||||
return CGM.EmitNullConstant(D.getType());
|
||||
}
|
||||
InConstantContext = true;
|
||||
}
|
||||
|
||||
QualType destType = D.getType();
|
||||
|
@ -1552,7 +1553,7 @@ llvm::Constant *ConstantEmitter::tryEmitPrivate(const Expr *E,
|
|||
if (destType->isReferenceType())
|
||||
Success = E->EvaluateAsLValue(Result, CGM.getContext());
|
||||
else
|
||||
Success = E->EvaluateAsRValue(Result, CGM.getContext());
|
||||
Success = E->EvaluateAsRValue(Result, CGM.getContext(), InConstantContext);
|
||||
|
||||
llvm::Constant *C;
|
||||
if (Success && !Result.HasSideEffects)
|
||||
|
|
|
@ -38,6 +38,9 @@ private:
|
|||
/// Whether the constant-emission failed.
|
||||
bool Failed = false;
|
||||
|
||||
/// Whether we're in a constant context.
|
||||
bool InConstantContext = false;
|
||||
|
||||
/// The AST address space where this (non-abstract) initializer is going.
|
||||
/// Used for generating appropriate placeholders.
|
||||
LangAS DestAddressSpace;
|
||||
|
|
|
@ -70,14 +70,14 @@ void test_constant_p() {
|
|||
const int j = 2;
|
||||
constexpr int k = 3;
|
||||
clang_analyzer_eval(__builtin_constant_p(42) == 1); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(__builtin_constant_p(i) == 0); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(__builtin_constant_p(i) == 0); // expected-warning {{UNKNOWN}}
|
||||
clang_analyzer_eval(__builtin_constant_p(j) == 1); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(__builtin_constant_p(k) == 1); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(__builtin_constant_p(i + 42) == 0); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(__builtin_constant_p(i + 42) == 0); // expected-warning {{UNKNOWN}}
|
||||
clang_analyzer_eval(__builtin_constant_p(j + 42) == 1); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(__builtin_constant_p(k + 42) == 1); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(__builtin_constant_p(" ") == 1); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(__builtin_constant_p(test_constant_p) == 0); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(__builtin_constant_p(test_constant_p) == 0); // expected-warning {{UNKNOWN}}
|
||||
clang_analyzer_eval(__builtin_constant_p(k - 3) == 0); // expected-warning {{FALSE}}
|
||||
clang_analyzer_eval(__builtin_constant_p(k - 3) == 1); // expected-warning {{TRUE}}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s -O2 | FileCheck %s
|
||||
|
||||
int a = 42;
|
||||
|
||||
inline int bcp(int x) {
|
||||
return __builtin_constant_p(x);
|
||||
}
|
||||
|
||||
/* --- Compound literals */
|
||||
|
||||
struct foo { int x, y; };
|
||||
|
||||
int y;
|
||||
struct foo f = (struct foo){ __builtin_constant_p(y), 42 };
|
||||
|
||||
struct foo test0(int expr) {
|
||||
// CHECK: define i64 @test0(i32 %expr)
|
||||
// CHECK: call i1 @llvm.is.constant.i32(i32 %expr)
|
||||
struct foo f = (struct foo){ __builtin_constant_p(expr), 42 };
|
||||
return f;
|
||||
}
|
||||
|
||||
/* --- Pointer types */
|
||||
|
||||
inline int test1_i(int *x) {
|
||||
return *x;
|
||||
}
|
||||
|
||||
int test1() {
|
||||
// CHECK: define i32 @test1
|
||||
// CHECK: add nsw i32 %0, -13
|
||||
// CHECK-NEXT: call i1 @llvm.is.constant.i32(i32 %sub)
|
||||
return bcp(test1_i(&a) - 13);
|
||||
}
|
||||
|
||||
int test2() {
|
||||
// CHECK: define i32 @test2
|
||||
// CHECK: ret i32 0
|
||||
return __builtin_constant_p(&a - 13);
|
||||
}
|
||||
|
||||
inline int test3_i(int *x) {
|
||||
return 42;
|
||||
}
|
||||
|
||||
int test3() {
|
||||
// CHECK: define i32 @test3
|
||||
// CHECK: ret i32 1
|
||||
return bcp(test3_i(&a) - 13);
|
||||
}
|
||||
|
||||
/* --- Aggregate types */
|
||||
|
||||
int b[] = {1, 2, 3};
|
||||
|
||||
int test4() {
|
||||
// CHECK: define i32 @test4
|
||||
// CHECK: ret i32 0
|
||||
return __builtin_constant_p(b);
|
||||
}
|
||||
|
||||
const char test5_c[] = {1, 2, 3, 0};
|
||||
|
||||
int test5() {
|
||||
// CHECK: define i32 @test5
|
||||
// CHECK: ret i32 0
|
||||
return __builtin_constant_p(test5_c);
|
||||
}
|
||||
|
||||
inline char test6_i(const char *x) {
|
||||
return x[1];
|
||||
}
|
||||
|
||||
int test6() {
|
||||
// CHECK: define i32 @test6
|
||||
// CHECK: ret i32 0
|
||||
return __builtin_constant_p(test6_i(test5_c));
|
||||
}
|
||||
|
||||
/* --- Non-constant global variables */
|
||||
|
||||
int test7() {
|
||||
// CHECK: define i32 @test7
|
||||
// CHECK: call i1 @llvm.is.constant.i32(i32 %0)
|
||||
return bcp(a);
|
||||
}
|
||||
|
||||
/* --- Constant global variables */
|
||||
|
||||
const int c = 42;
|
||||
|
||||
int test8() {
|
||||
// CHECK: define i32 @test8
|
||||
// CHECK: ret i32 1
|
||||
return bcp(c);
|
||||
}
|
||||
|
||||
/* --- Array types */
|
||||
|
||||
int arr[] = { 1, 2, 3 };
|
||||
const int c_arr[] = { 1, 2, 3 };
|
||||
|
||||
int test9() {
|
||||
// CHECK: define i32 @test9
|
||||
// CHECK: call i1 @llvm.is.constant.i32(i32 %0)
|
||||
return __builtin_constant_p(arr[2]);
|
||||
}
|
||||
|
||||
int test10() {
|
||||
// CHECK: define i32 @test10
|
||||
// CHECK: ret i32 1
|
||||
return __builtin_constant_p(c_arr[2]);
|
||||
}
|
||||
|
||||
int test11() {
|
||||
// CHECK: define i32 @test11
|
||||
// CHECK: ret i32 0
|
||||
return __builtin_constant_p(c_arr);
|
||||
}
|
||||
|
||||
/* --- Function pointers */
|
||||
|
||||
int test12() {
|
||||
// CHECK: define i32 @test12
|
||||
// CHECK: ret i32 0
|
||||
return __builtin_constant_p(&test10);
|
||||
}
|
||||
|
||||
int test13() {
|
||||
// CHECK: define i32 @test13
|
||||
// CHECK: ret i32 1
|
||||
return __builtin_constant_p(&test10 != 0);
|
||||
}
|
||||
|
||||
typedef unsigned long uintptr_t;
|
||||
#define assign(p, v) ({ \
|
||||
uintptr_t _r_a_p__v = (uintptr_t)(v); \
|
||||
if (__builtin_constant_p(v) && _r_a_p__v == (uintptr_t)0) { \
|
||||
union { \
|
||||
uintptr_t __val; \
|
||||
char __c[1]; \
|
||||
} __u = { \
|
||||
.__val = (uintptr_t)_r_a_p__v \
|
||||
}; \
|
||||
*(volatile unsigned int*)&p = *(unsigned int*)(__u.__c); \
|
||||
__u.__val; \
|
||||
} \
|
||||
_r_a_p__v; \
|
||||
})
|
||||
|
||||
typedef void fn_p(void);
|
||||
extern fn_p *dest_p;
|
||||
|
||||
static void src_fn(void) {
|
||||
}
|
||||
|
||||
void test14() {
|
||||
assign(dest_p, src_fn);
|
||||
}
|
||||
|
||||
extern int test15_v;
|
||||
|
||||
struct { const char *t; int a; } test15[] = {
|
||||
{ "tag", __builtin_constant_p(test15_v) && !test15_v ? 1 : 0 }
|
||||
};
|
||||
|
||||
extern char test16_v;
|
||||
struct { int a; } test16 = { __builtin_constant_p(test16_v) };
|
Loading…
Reference in New Issue