"Enhance" CheckArithmeticConstantExpression to accept ?: with a constant
condition as a constant even if the unevaluated side is a not a constant. We don't do this when extensions are off, and we emit a warning when this happens: t.c:22:11: warning: expression is not a constant, but is accepted as one by GNU extensions short t = __builtin_constant_p(5353) ? 42 : somefunc(); ^ ~~~~~~~~~~ suggestions for improvement are welcome. This is obviously horrible, but is required for real-world code. llvm-svn: 57153
This commit is contained in:
parent
4deaa4ea24
commit
c43467526d
|
@ -1096,6 +1096,8 @@ DIAG(warn_typecheck_cond_incompatible_pointers, WARNING,
|
|||
"pointer type mismatch ('%0' and '%1')")
|
||||
DIAG(err_typecheck_choose_expr_requires_constant, ERROR,
|
||||
"'__builtin_choose_expr' requires a constant expression")
|
||||
DIAG(ext_typecheck_expression_not_constant_but_accepted, EXTENSION,
|
||||
"expression is not a constant, but is accepted as one by GNU extensions")
|
||||
DIAG(warn_unused_expr, WARNING,
|
||||
"expression result unused")
|
||||
DIAG(err_pascal_string_too_long, ERROR,
|
||||
|
|
|
@ -1190,12 +1190,47 @@ bool Sema::CheckArithmeticConstantExpression(const Expr* Init) {
|
|||
}
|
||||
case Expr::ConditionalOperatorClass: {
|
||||
const ConditionalOperator *Exp = cast<ConditionalOperator>(Init);
|
||||
if (CheckArithmeticConstantExpression(Exp->getCond()))
|
||||
|
||||
// If GNU extensions are disabled, we require all operands to be arithmetic
|
||||
// constant expressions.
|
||||
if (getLangOptions().NoExtensions) {
|
||||
return CheckArithmeticConstantExpression(Exp->getCond()) ||
|
||||
(Exp->getLHS() && CheckArithmeticConstantExpression(Exp->getLHS())) ||
|
||||
CheckArithmeticConstantExpression(Exp->getRHS());
|
||||
}
|
||||
|
||||
// Otherwise, we have to emulate some of the behavior of fold here.
|
||||
// Basically GCC treats things like "4 ? 1 : somefunc()" as a constant
|
||||
// because it can constant fold things away. To retain compatibility with
|
||||
// GCC code, we see if we can fold the condition to a constant (which we
|
||||
// should always be able to do in theory). If so, we only require the
|
||||
// specified arm of the conditional to be a constant. This is a horrible
|
||||
// hack, but is require by real world code that uses __builtin_constant_p.
|
||||
APValue Val;
|
||||
if (!Exp->getCond()->tryEvaluate(Val, Context)) {
|
||||
// If the tryEvaluate couldn't fold it, CheckArithmeticConstantExpression
|
||||
// won't be able to either. Use it to emit the diagnostic though.
|
||||
bool Res = CheckArithmeticConstantExpression(Exp->getCond());
|
||||
assert(Res && "tryEvaluate couldn't evaluate this constant?");
|
||||
return Res;
|
||||
}
|
||||
|
||||
// Verify that the side following the condition is also a constant.
|
||||
const Expr *TrueSide = Exp->getLHS(), *FalseSide = Exp->getRHS();
|
||||
if (Val.getInt() == 0)
|
||||
std::swap(TrueSide, FalseSide);
|
||||
|
||||
if (TrueSide && CheckArithmeticConstantExpression(TrueSide))
|
||||
return true;
|
||||
if (Exp->getLHS() &&
|
||||
CheckArithmeticConstantExpression(Exp->getLHS()))
|
||||
return true;
|
||||
return CheckArithmeticConstantExpression(Exp->getRHS());
|
||||
|
||||
// Okay, the evaluated side evaluates to a constant, so we accept this.
|
||||
// Check to see if the other side is obviously not a constant. If so,
|
||||
// emit a warning that this is a GNU extension.
|
||||
if (FalseSide && !FalseSide->tryEvaluate(Val, Context))
|
||||
Diag(Init->getExprLoc(),
|
||||
diag::ext_typecheck_expression_not_constant_but_accepted,
|
||||
FalseSide->getSourceRange());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1211,20 +1246,8 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
|
|||
return CheckForConstantInitializer(e->getInitializer(), DclT);
|
||||
|
||||
if (Init->getType()->isReferenceType()) {
|
||||
// FIXME: Work out how the heck reference types work
|
||||
// FIXME: Work out how the heck references work.
|
||||
return false;
|
||||
#if 0
|
||||
// A reference is constant if the address of the expression
|
||||
// is constant
|
||||
// We look through initlists here to simplify
|
||||
// CheckAddressConstantExpressionLValue.
|
||||
if (InitListExpr *Exp = dyn_cast<InitListExpr>(Init)) {
|
||||
assert(Exp->getNumInits() > 0 &&
|
||||
"Refernce initializer cannot be empty");
|
||||
Init = Exp->getInit(0);
|
||||
}
|
||||
return CheckAddressConstantExpressionLValue(Init);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (InitListExpr *Exp = dyn_cast<InitListExpr>(Init)) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: clang -fsyntax-only %s
|
||||
// RUN: clang -fsyntax-only %s -verify -pedantic
|
||||
|
||||
// Math stuff
|
||||
|
||||
|
@ -13,6 +13,11 @@ long double g5 = __builtin_infl();
|
|||
|
||||
extern int f();
|
||||
|
||||
int h0 = __builtin_types_compatible_p(int,float);
|
||||
int h0 = __builtin_types_compatible_p(int,float); // expected-warning {{extension}}
|
||||
//int h1 = __builtin_choose_expr(1, 10, f());
|
||||
//int h2 = __builtin_expect(0, 0);
|
||||
|
||||
short somefunc();
|
||||
|
||||
short t = __builtin_constant_p(5353) ? 42 : somefunc(); // expected-warning {{expression is not a constant, but is accepted as one by GNU extensions}}
|
||||
|
||||
|
|
Loading…
Reference in New Issue