diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-12-09 02:04:48 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-12-09 02:04:48 +0000 |
commit | e052d46f4db91f9ba572859ffc984e85cbf5d5ff (patch) | |
tree | 9baebdec96646ad35d1242ca1f844311acab7d39 /lib/AST/ExprConstant.cpp | |
parent | 6a1db484f32eb791840dd55a8d45c86ff5bd0834 (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.cpp | 52 |
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); |