aboutsummaryrefslogtreecommitdiff
path: root/lib/AST
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST')
-rw-r--r--lib/AST/APValue.cpp17
-rw-r--r--lib/AST/Expr.cpp27
-rw-r--r--lib/AST/ExprConstant.cpp46
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);
}