diff options
author | Eli Friedman <eli.friedman@gmail.com> | 2012-01-04 23:13:47 +0000 |
---|---|---|
committer | Eli Friedman <eli.friedman@gmail.com> | 2012-01-04 23:13:47 +0000 |
commit | 65639284118d54ddf2e51a05d2ffccda567fe246 (patch) | |
tree | 66b7a7ae4545db073ada0549d8af683c5c2b4231 /lib/AST/ExprConstant.cpp | |
parent | 08f7760eb2bc25ba3335169be83f7ba492860135 (diff) |
Add an APValue representation for the difference between two address-of-label expressions. Add support to Evaluate and CGExprConstant for generating/handling them. Remove the special-case for such differences in Expr::isConstantInitializer.
With that done, remove a bunch of buggy code from CGExprConstant for handling scalar expressions which is no longer necessary.
Fixes PR11705.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147561 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r-- | lib/AST/ExprConstant.cpp | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 4aed81215c..fc214bfa80 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -210,6 +210,8 @@ namespace { CCValue(const ValueDecl *D, bool IsDerivedMember, ArrayRef<const CXXRecordDecl*> Path) : APValue(D, IsDerivedMember, Path) {} + CCValue(const AddrLabelExpr* LHSExpr, const AddrLabelExpr* RHSExpr) : + APValue(LHSExpr, RHSExpr) {} CallStackFrame *getLValueFrame() const { assert(getKind() == LValue); @@ -856,6 +858,7 @@ static bool HandleConversionToBool(const CCValue &Val, bool &Result) { case APValue::Array: case APValue::Struct: case APValue::Union: + case APValue::AddrLabelDiff: return false; } @@ -3997,6 +4000,23 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // Reject differing bases from the normal codepath; we special-case // comparisons to null. if (!HasSameBase(LHSValue, RHSValue)) { + if (E->getOpcode() == BO_Sub) { + // Handle &&A - &&B. + // FIXME: We're missing a check that both labels have the same + // associated function; I'm not sure how to write this check. + if (!LHSValue.Offset.isZero() || !RHSValue.Offset.isZero()) + return false; + const Expr *LHSExpr = LHSValue.Base.dyn_cast<const Expr*>(); + const Expr *RHSExpr = LHSValue.Base.dyn_cast<const Expr*>(); + if (!LHSExpr || !RHSExpr) + return false; + const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr); + const AddrLabelExpr *RHSAddrExpr = dyn_cast<AddrLabelExpr>(RHSExpr); + if (!LHSAddrExpr || !RHSAddrExpr) + return false; + Result = CCValue(LHSAddrExpr, RHSAddrExpr); + return true; + } // Inequalities and subtractions between unrelated pointers have // unspecified or undefined behavior. if (!E->isEqualityOp()) @@ -4091,6 +4111,25 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return true; } + if (E->getOpcode() == BO_Sub && LHSVal.isLValue() && RHSVal.isLValue()) { + // Handle (intptr_t)&&A - (intptr_t)&&B. + // FIXME: We're missing a check that both labels have the same + // associated function; I'm not sure how to write this check. + if (!LHSVal.getLValueOffset().isZero() || + !RHSVal.getLValueOffset().isZero()) + return false; + const Expr *LHSExpr = LHSVal.getLValueBase().dyn_cast<const Expr*>(); + const Expr *RHSExpr = RHSVal.getLValueBase().dyn_cast<const Expr*>(); + if (!LHSExpr || !RHSExpr) + return false; + const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr); + const AddrLabelExpr *RHSAddrExpr = dyn_cast<AddrLabelExpr>(RHSExpr); + if (!LHSAddrExpr || !RHSAddrExpr) + return false; + Result = CCValue(LHSAddrExpr, RHSAddrExpr); + return true; + } + // All the following cases expect both operands to be an integer if (!LHSVal.isInt() || !RHSVal.isInt()) return Error(E); @@ -4398,6 +4437,13 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { return false; if (!Result.isInt()) { + // Allow casts of address-of-label differences if they are no-ops + // or narrowing. (The narrowing case isn't actually guaranteed to + // be constant-evaluatable except in some narrow cases which are hard + // to detect here. We let it through on the assumption the user knows + // what they are doing.) + if (Result.isAddrLabelDiff()) + return Info.Ctx.getTypeSize(DestType) <= Info.Ctx.getTypeSize(SrcType); // Only allow casts of lvalues if they are lossless. return Info.Ctx.getTypeSize(DestType) == Info.Ctx.getTypeSize(SrcType); } |