diff options
Diffstat (limited to 'lib/AST')
-rw-r--r-- | lib/AST/APValue.cpp | 17 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 27 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 46 |
3 files changed, 62 insertions, 28 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 2a68341e5a..b8942c3310 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -149,6 +149,8 @@ const APValue &APValue::operator=(const APValue &RHS) { MakeMemberPointer(RHS.getMemberPointerDecl(), RHS.isMemberPointerToDerivedMember(), RHS.getMemberPointerPath()); + else if (RHS.isAddrLabelDiff()) + MakeAddrLabelDiff(); } if (isInt()) setInt(RHS.getInt()); @@ -177,8 +179,11 @@ const APValue &APValue::operator=(const APValue &RHS) { getStructBase(I) = RHS.getStructBase(I); for (unsigned I = 0, N = RHS.getStructNumFields(); I != N; ++I) getStructField(I) = RHS.getStructField(I); - } else if (isUnion()) + } else if (isUnion()) { setUnion(RHS.getUnionField(), RHS.getUnionValue()); + } else if (isAddrLabelDiff()) { + setAddrLabelDiff(RHS.getAddrLabelDiffLHS(), RHS.getAddrLabelDiffRHS()); + } return *this; } @@ -203,6 +208,8 @@ void APValue::MakeUninit() { ((UnionData*)(char*)Data)->~UnionData(); else if (Kind == MemberPointer) ((MemberPointerData*)(char*)Data)->~MemberPointerData(); + else if (Kind == AddrLabelDiff) + ((AddrLabelDiffData*)(char*)Data)->~AddrLabelDiffData(); Kind = Uninitialized; } @@ -285,6 +292,9 @@ void APValue::dump(raw_ostream &OS) const { case MemberPointer: OS << "MemberPointer: <todo>"; return; + case AddrLabelDiff: + OS << "AddrLabelDiff: <todo>"; + return; } llvm_unreachable("Unknown APValue kind!"); } @@ -472,6 +482,11 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ } Out << "0"; return; + case APValue::AddrLabelDiff: + Out << "&&" << getAddrLabelDiffLHS()->getLabel()->getName(); + Out << " - "; + Out << "&&" << getAddrLabelDiffRHS()->getLabel()->getName(); + return; } llvm_unreachable("Unknown APValue kind!"); } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 9f87161290..bbf54112c8 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2530,16 +2530,6 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { return Exp->getSubExpr()->isConstantInitializer(Ctx, false); break; } - case BinaryOperatorClass: { - // Special case &&foo - &&bar. It would be nice to generalize this somehow - // but this handles the common case. - const BinaryOperator *Exp = cast<BinaryOperator>(this); - if (Exp->getOpcode() == BO_Sub && - isa<AddrLabelExpr>(Exp->getLHS()->IgnoreParenNoopCasts(Ctx)) && - isa<AddrLabelExpr>(Exp->getRHS()->IgnoreParenNoopCasts(Ctx))) - return true; - break; - } case CXXFunctionalCastExprClass: case CXXStaticCastExprClass: case ImplicitCastExprClass: @@ -2558,23 +2548,6 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { CE->getCastKind() == CK_ConstructorConversion) return CE->getSubExpr()->isConstantInitializer(Ctx, false); - // Handle things like (int)(&&x-&&y). It's a bit nasty, but we support it. - if (CE->getCastKind() == CK_IntegralCast) { - const Expr *E = CE->getSubExpr()->IgnoreParenNoopCasts(Ctx); - while (const CastExpr *InnerCE = dyn_cast<CastExpr>(E)) { - if (InnerCE->getCastKind() != CK_IntegralCast) - break; - E = InnerCE->getSubExpr()->IgnoreParenNoopCasts(Ctx); - } - - if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { - if (BO->getOpcode() == BO_Sub && - isa<AddrLabelExpr>(BO->getLHS()->IgnoreParenNoopCasts(Ctx)) && - isa<AddrLabelExpr>(BO->getRHS()->IgnoreParenNoopCasts(Ctx))) - return true; - } - } - break; } case MaterializeTemporaryExprClass: 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); } |