[cfe-commits] r57153 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def lib/Sema/SemaDecl.cpp test/Sema/constant-builtins.c
Chris Lattner
sabre at nondot.org
Sun Oct 5 22:42:40 PDT 2008
Author: lattner
Date: Mon Oct 6 00:42:39 2008
New Revision: 57153
URL: http://llvm.org/viewvc/llvm-project?rev=57153&view=rev
Log:
"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.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/Sema/constant-builtins.c
Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=57153&r1=57152&r2=57153&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Mon Oct 6 00:42:39 2008
@@ -1096,6 +1096,8 @@
"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,
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=57153&r1=57152&r2=57153&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Oct 6 00:42:39 2008
@@ -1190,12 +1190,47 @@
}
case Expr::ConditionalOperatorClass: {
const ConditionalOperator *Exp = cast<ConditionalOperator>(Init);
- if (CheckArithmeticConstantExpression(Exp->getCond()))
- return true;
- if (Exp->getLHS() &&
- CheckArithmeticConstantExpression(Exp->getLHS()))
+
+ // 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;
- 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 @@
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)) {
Modified: cfe/trunk/test/Sema/constant-builtins.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/constant-builtins.c?rev=57153&r1=57152&r2=57153&view=diff
==============================================================================
--- cfe/trunk/test/Sema/constant-builtins.c (original)
+++ cfe/trunk/test/Sema/constant-builtins.c Mon Oct 6 00:42:39 2008
@@ -1,4 +1,4 @@
-// RUN: clang -fsyntax-only %s
+// RUN: clang -fsyntax-only %s -verify -pedantic
// Math stuff
@@ -13,6 +13,11 @@
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}}
+
More information about the cfe-commits
mailing list