aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2011-12-09 02:04:48 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2011-12-09 02:04:48 +0000
commite052d46f4db91f9ba572859ffc984e85cbf5d5ff (patch)
tree9baebdec96646ad35d1242ca1f844311acab7d39 /lib/AST/ExprConstant.cpp
parent6a1db484f32eb791840dd55a8d45c86ff5bd0834 (diff)
Replace the implementation of __builtin_constant_p (which was based on the GCC
documentation) with one based on what GCC's __builtin_constant_p is actually intended to do (discovered by asking a friendly GCC developer). In particular, an expression which folds to a pointer is now only considered to be a "constant" by this builtin if it refers to the first character in a string literal. This fixes a rather subtle wrong-code issue when building with glibc. Given: const char cs[4] = "abcd"; int f(const char *p) { return strncmp(p, cs, 4); } ... the macro magic for strncmp produces a (potentially crashing) call to strlen(cs), because it expands to an expression starting with: __builtin_constant_p(cs) && strlen(cs) < 4 ? /* ... */ Under the secret true meaning of __builtin_constant_p, this is guaranteed to be safe! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146236 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r--lib/AST/ExprConstant.cpp52
1 files changed, 47 insertions, 5 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 9b9150c148..cbb75db255 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -3035,11 +3035,53 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_classify_type:
return Success(EvaluateBuiltinClassifyType(E), E);
- case Builtin::BI__builtin_constant_p:
- // __builtin_constant_p always has one operand: it returns true if that
- // operand can be folded, false otherwise.
- return Success(E->getArg(0)->isEvaluatable(Info.Ctx), E);
-
+ case Builtin::BI__builtin_constant_p: {
+ const Expr *Arg = E->getArg(0);
+ QualType ArgType = Arg->getType();
+ // __builtin_constant_p always has one operand. The rules which gcc follows
+ // are not precisely documented, but are as follows:
+ //
+ // - If the operand is of integral, floating, complex or enumeration type,
+ // and can be folded to a known value of that type, it returns 1.
+ // - If the operand and can be folded to a pointer to the first character
+ // of a string literal (or such a pointer cast to an integral type), it
+ // returns 1.
+ //
+ // Otherwise, it returns 0.
+ //
+ // FIXME: GCC also intends to return 1 for literals of aggregate types, but
+ // its support for this does not currently work.
+ int IsConstant = 0;
+ if (ArgType->isIntegralOrEnumerationType()) {
+ // Note, a pointer cast to an integral type is only a constant if it is
+ // a pointer to the first character of a string literal.
+ Expr::EvalResult Result;
+ if (Arg->EvaluateAsRValue(Result, Info.Ctx) && !Result.HasSideEffects) {
+ APValue &V = Result.Val;
+ if (V.getKind() == APValue::LValue) {
+ if (const Expr *E = V.getLValueBase().dyn_cast<const Expr*>())
+ IsConstant = isa<StringLiteral>(E) && V.getLValueOffset().isZero();
+ } else {
+ IsConstant = 1;
+ }
+ }
+ } else if (ArgType->isFloatingType() || ArgType->isAnyComplexType()) {
+ IsConstant = Arg->isEvaluatable(Info.Ctx);
+ } else if (ArgType->isPointerType() || Arg->isGLValue()) {
+ LValue LV;
+ // Use a separate EvalInfo: ignore constexpr parameter and 'this' bindings
+ // during the check.
+ Expr::EvalStatus Status;
+ EvalInfo SubInfo(Info.Ctx, Status);
+ if ((Arg->isGLValue() ? EvaluateLValue(Arg, LV, SubInfo)
+ : EvaluatePointer(Arg, LV, SubInfo)) &&
+ !Status.HasSideEffects)
+ if (const Expr *E = LV.getLValueBase().dyn_cast<const Expr*>())
+ IsConstant = isa<StringLiteral>(E) && LV.getLValueOffset().isZero();
+ }
+
+ return Success(IsConstant, E);
+ }
case Builtin::BI__builtin_eh_return_data_regno: {
int Operand = E->getArg(0)->EvaluateKnownConstInt(Info.Ctx).getZExtValue();
Operand = Info.Ctx.getTargetInfo().getEHDataRegisterNumber(Operand);