summaryrefslogtreecommitdiff
path: root/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r--lib/AST/ExprConstant.cpp579
1 files changed, 460 insertions, 119 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 7d7ca9924c85..3d7f2dca7a2f 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -201,6 +201,7 @@ namespace {
/// Determine whether this is a one-past-the-end pointer.
bool isOnePastTheEnd() const {
+ assert(!Invalid);
if (IsOnePastTheEnd)
return true;
if (MostDerivedArraySize &&
@@ -1308,7 +1309,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
}
// Does this refer one past the end of some object?
- if (Designator.isOnePastTheEnd()) {
+ if (!Designator.Invalid && Designator.isOnePastTheEnd()) {
const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
Info.Diag(Loc, diag::note_constexpr_past_end, 1)
<< !Designator.Entries.empty() << !!VD << VD;
@@ -1328,7 +1329,7 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
// C++1y: A constant initializer for an object o [...] may also invoke
// constexpr constructors for o and its subobjects even if those objects
// are of non-literal class types.
- if (Info.getLangOpts().CPlusPlus1y && This &&
+ if (Info.getLangOpts().CPlusPlus14 && This &&
Info.EvaluatingDecl == This->getLValueBase())
return true;
@@ -1421,6 +1422,17 @@ static bool IsWeakLValue(const LValue &Value) {
return Decl && Decl->isWeak();
}
+static bool isZeroSized(const LValue &Value) {
+ const ValueDecl *Decl = GetLValueBaseDecl(Value);
+ if (Decl && isa<VarDecl>(Decl)) {
+ QualType Ty = Decl->getType();
+ if (Ty->isArrayType())
+ return Ty->isIncompleteType() ||
+ Decl->getASTContext().getTypeSize(Ty) == 0;
+ }
+ return false;
+}
+
static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) {
// A null base expression indicates a null pointer. These are always
// evaluatable, and they are false unless the offset is zero.
@@ -2020,7 +2032,9 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived,
/// Extract the value of a character from a string literal.
static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
uint64_t Index) {
- // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant
+ // FIXME: Support ObjCEncodeExpr, MakeStringConstant
+ if (auto PE = dyn_cast<PredefinedExpr>(Lit))
+ Lit = PE->getFunctionName();
const StringLiteral *S = cast<StringLiteral>(Lit);
const ConstantArrayType *CAT =
Info.Ctx.getAsConstantArrayType(S->getType());
@@ -2079,6 +2093,64 @@ static void expandArray(APValue &Array, unsigned Index) {
Array.swap(NewValue);
}
+/// Determine whether a type would actually be read by an lvalue-to-rvalue
+/// conversion. If it's of class type, we may assume that the copy operation
+/// is trivial. Note that this is never true for a union type with fields
+/// (because the copy always "reads" the active member) and always true for
+/// a non-class type.
+static bool isReadByLvalueToRvalueConversion(QualType T) {
+ CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ if (!RD || (RD->isUnion() && !RD->field_empty()))
+ return true;
+ if (RD->isEmpty())
+ return false;
+
+ for (auto *Field : RD->fields())
+ if (isReadByLvalueToRvalueConversion(Field->getType()))
+ return true;
+
+ for (auto &BaseSpec : RD->bases())
+ if (isReadByLvalueToRvalueConversion(BaseSpec.getType()))
+ return true;
+
+ return false;
+}
+
+/// Diagnose an attempt to read from any unreadable field within the specified
+/// type, which might be a class type.
+static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E,
+ QualType T) {
+ CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ if (!RD)
+ return false;
+
+ if (!RD->hasMutableFields())
+ return false;
+
+ for (auto *Field : RD->fields()) {
+ // If we're actually going to read this field in some way, then it can't
+ // be mutable. If we're in a union, then assigning to a mutable field
+ // (even an empty one) can change the active member, so that's not OK.
+ // FIXME: Add core issue number for the union case.
+ if (Field->isMutable() &&
+ (RD->isUnion() || isReadByLvalueToRvalueConversion(Field->getType()))) {
+ Info.Diag(E, diag::note_constexpr_ltor_mutable, 1) << Field;
+ Info.Note(Field->getLocation(), diag::note_declared_at);
+ return true;
+ }
+
+ if (diagnoseUnreadableFields(Info, E, Field->getType()))
+ return true;
+ }
+
+ for (auto &BaseSpec : RD->bases())
+ if (diagnoseUnreadableFields(Info, E, BaseSpec.getType()))
+ return true;
+
+ // All mutable fields were empty, and thus not actually read.
+ return false;
+}
+
/// Kinds of access we can perform on an object, for diagnostics.
enum AccessKinds {
AK_Read,
@@ -2134,6 +2206,14 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
}
if (I == N) {
+ // If we are reading an object of class type, there may still be more
+ // things we need to check: if there are any mutable subobjects, we
+ // cannot perform this read. (This only happens when performing a trivial
+ // copy or assignment.)
+ if (ObjType->isRecordType() && handler.AccessKind == AK_Read &&
+ diagnoseUnreadableFields(Info, E, ObjType))
+ return handler.failed();
+
if (!handler.found(*O, ObjType))
return false;
@@ -2490,7 +2570,7 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
// Unless we're looking at a local variable or argument in a constexpr call,
// the variable we're reading must be const.
if (!Frame) {
- if (Info.getLangOpts().CPlusPlus1y &&
+ if (Info.getLangOpts().CPlusPlus14 &&
VD == Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()) {
// OK, we can read and modify an object if we're in the process of
// evaluating its initializer, because its lifetime began in this
@@ -2606,7 +2686,7 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
//
// FIXME: Not all local state is mutable. Allow local constant subobjects
// to be read here (but take care with 'mutable' fields).
- if (Frame && Info.getLangOpts().CPlusPlus1y &&
+ if (Frame && Info.getLangOpts().CPlusPlus14 &&
(Info.EvalStatus.HasSideEffects || Info.keepEvaluatingAfterFailure()))
return CompleteObject();
@@ -2648,10 +2728,10 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
return false;
CompleteObject LitObj(&Lit, Base->getType());
return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal);
- } else if (isa<StringLiteral>(Base)) {
+ } else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) {
// We represent a string literal array as an lvalue pointing at the
// corresponding expression, rather than building an array of chars.
- // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant
+ // FIXME: Support ObjCEncodeExpr, MakeStringConstant
APValue Str(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0);
CompleteObject StrObj(&Str, Base->getType());
return extractSubobject(Info, Conv, StrObj, LVal.Designator, RVal);
@@ -2668,7 +2748,7 @@ static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal,
if (LVal.Designator.Invalid)
return false;
- if (!Info.getLangOpts().CPlusPlus1y) {
+ if (!Info.getLangOpts().CPlusPlus14) {
Info.Diag(E);
return false;
}
@@ -2789,7 +2869,7 @@ static bool handleCompoundAssignment(
if (LVal.Designator.Invalid)
return false;
- if (!Info.getLangOpts().CPlusPlus1y) {
+ if (!Info.getLangOpts().CPlusPlus14) {
Info.Diag(E);
return false;
}
@@ -2938,7 +3018,7 @@ static bool handleIncDec(EvalInfo &Info, const Expr *E, const LValue &LVal,
if (LVal.Designator.Invalid)
return false;
- if (!Info.getLangOpts().CPlusPlus1y) {
+ if (!Info.getLangOpts().CPlusPlus14) {
Info.Diag(E);
return false;
}
@@ -3588,6 +3668,22 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
return false;
}
+/// Determine if a class has any fields that might need to be copied by a
+/// trivial copy or move operation.
+static bool hasFields(const CXXRecordDecl *RD) {
+ if (!RD || RD->isEmpty())
+ return false;
+ for (auto *FD : RD->fields()) {
+ if (FD->isUnnamedBitfield())
+ continue;
+ return true;
+ }
+ for (auto &Base : RD->bases())
+ if (hasFields(Base.getType()->getAsCXXRecordDecl()))
+ return true;
+ return false;
+}
+
namespace {
typedef SmallVector<APValue, 8> ArgVector;
}
@@ -3626,8 +3722,12 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
// For a trivial copy or move assignment, perform an APValue copy. This is
// essential for unions, where the operations performed by the assignment
// operator cannot be represented as statements.
+ //
+ // Skip this for non-union classes with no fields; in that case, the defaulted
+ // copy/move does not actually read the object.
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee);
- if (MD && MD->isDefaulted() && MD->isTrivial()) {
+ if (MD && MD->isDefaulted() && MD->isTrivial() &&
+ (MD->getParent()->isUnion() || hasFields(MD->getParent()))) {
assert(This &&
(MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()));
LValue RHS;
@@ -3684,11 +3784,18 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
}
// For a trivial copy or move constructor, perform an APValue copy. This is
- // essential for unions, where the operations performed by the constructor
- // cannot be represented by ctor-initializers.
+ // essential for unions (or classes with anonymous union members), where the
+ // operations performed by the constructor cannot be represented by
+ // ctor-initializers.
+ //
+ // Skip this for empty non-union classes; we should not perform an
+ // lvalue-to-rvalue conversion on them because their copy constructor does not
+ // actually read them.
if (Definition->isDefaulted() &&
((Definition->isCopyConstructor() && Definition->isTrivial()) ||
- (Definition->isMoveConstructor() && Definition->isTrivial()))) {
+ (Definition->isMoveConstructor() && Definition->isTrivial())) &&
+ (Definition->getParent()->isUnion() ||
+ hasFields(Definition->getParent()))) {
LValue RHS;
RHS.setFrom(Info.Ctx, ArgValues[0]);
return handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
@@ -3985,7 +4092,7 @@ public:
const FunctionDecl *FD = nullptr;
LValue *This = nullptr, ThisVal;
- ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
+ auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
bool HasQualifier = false;
// Extract function decl and 'this' pointer from the callee.
@@ -4148,7 +4255,7 @@ public:
return VisitUnaryPostIncDec(UO);
}
bool VisitUnaryPostIncDec(const UnaryOperator *UO) {
- if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure())
+ if (!Info.getLangOpts().CPlusPlus14 && !Info.keepEvaluatingAfterFailure())
return Error(UO);
LValue LVal;
@@ -4573,7 +4680,7 @@ bool LValueExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
}
bool LValueExprEvaluator::VisitUnaryPreIncDec(const UnaryOperator *UO) {
- if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure())
+ if (!Info.getLangOpts().CPlusPlus14 && !Info.keepEvaluatingAfterFailure())
return Error(UO);
if (!this->Visit(UO->getSubExpr()))
@@ -4586,7 +4693,7 @@ bool LValueExprEvaluator::VisitUnaryPreIncDec(const UnaryOperator *UO) {
bool LValueExprEvaluator::VisitCompoundAssignOperator(
const CompoundAssignOperator *CAO) {
- if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure())
+ if (!Info.getLangOpts().CPlusPlus14 && !Info.keepEvaluatingAfterFailure())
return Error(CAO);
APValue RHS;
@@ -4608,7 +4715,7 @@ bool LValueExprEvaluator::VisitCompoundAssignOperator(
}
bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) {
- if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure())
+ if (!Info.getLangOpts().CPlusPlus14 && !Info.keepEvaluatingAfterFailure())
return Error(E);
APValue NewVal;
@@ -4733,6 +4840,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
+ case CK_AddressSpaceConversion:
if (!Visit(SubExpr))
return false;
// Bitcasts to cv void* are static_casts, not reinterpret_casts, so are
@@ -4818,6 +4926,38 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return ExprEvaluatorBaseTy::VisitCastExpr(E);
}
+static CharUnits GetAlignOfType(EvalInfo &Info, QualType T) {
+ // C++ [expr.alignof]p3:
+ // When alignof is applied to a reference type, the result is the
+ // alignment of the referenced type.
+ if (const ReferenceType *Ref = T->getAs<ReferenceType>())
+ T = Ref->getPointeeType();
+
+ // __alignof is defined to return the preferred alignment.
+ return Info.Ctx.toCharUnitsFromBits(
+ Info.Ctx.getPreferredTypeAlign(T.getTypePtr()));
+}
+
+static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E) {
+ E = E->IgnoreParens();
+
+ // The kinds of expressions that we have special-case logic here for
+ // should be kept up to date with the special checks for those
+ // expressions in Sema.
+
+ // alignof decl is always accepted, even if it doesn't make sense: we default
+ // to 1 in those cases.
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ return Info.Ctx.getDeclAlign(DRE->getDecl(),
+ /*RefAsPointee*/true);
+
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
+ return Info.Ctx.getDeclAlign(ME->getMemberDecl(),
+ /*RefAsPointee*/true);
+
+ return GetAlignOfType(Info, E->getType());
+}
+
bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (IsStringLiteralCall(E))
return Success(E);
@@ -4825,7 +4965,71 @@ bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
switch (E->getBuiltinCallee()) {
case Builtin::BI__builtin_addressof:
return EvaluateLValue(E->getArg(0), Result, Info);
+ case Builtin::BI__builtin_assume_aligned: {
+ // We need to be very careful here because: if the pointer does not have the
+ // asserted alignment, then the behavior is undefined, and undefined
+ // behavior is non-constant.
+ if (!EvaluatePointer(E->getArg(0), Result, Info))
+ return false;
+
+ LValue OffsetResult(Result);
+ APSInt Alignment;
+ if (!EvaluateInteger(E->getArg(1), Alignment, Info))
+ return false;
+ CharUnits Align = CharUnits::fromQuantity(getExtValue(Alignment));
+
+ if (E->getNumArgs() > 2) {
+ APSInt Offset;
+ if (!EvaluateInteger(E->getArg(2), Offset, Info))
+ return false;
+
+ int64_t AdditionalOffset = -getExtValue(Offset);
+ OffsetResult.Offset += CharUnits::fromQuantity(AdditionalOffset);
+ }
+
+ // If there is a base object, then it must have the correct alignment.
+ if (OffsetResult.Base) {
+ CharUnits BaseAlignment;
+ if (const ValueDecl *VD =
+ OffsetResult.Base.dyn_cast<const ValueDecl*>()) {
+ BaseAlignment = Info.Ctx.getDeclAlign(VD);
+ } else {
+ BaseAlignment =
+ GetAlignOfExpr(Info, OffsetResult.Base.get<const Expr*>());
+ }
+
+ if (BaseAlignment < Align) {
+ Result.Designator.setInvalid();
+ // FIXME: Quantities here cast to integers because the plural modifier
+ // does not work on APSInts yet.
+ CCEDiag(E->getArg(0),
+ diag::note_constexpr_baa_insufficient_alignment) << 0
+ << (int) BaseAlignment.getQuantity()
+ << (unsigned) getExtValue(Alignment);
+ return false;
+ }
+ }
+
+ // The offset must also have the correct alignment.
+ if (OffsetResult.Offset.RoundUpToAlignment(Align) != OffsetResult.Offset) {
+ Result.Designator.setInvalid();
+ APSInt Offset(64, false);
+ Offset = OffsetResult.Offset.getQuantity();
+ if (OffsetResult.Base)
+ CCEDiag(E->getArg(0),
+ diag::note_constexpr_baa_insufficient_alignment) << 1
+ << (int) getExtValue(Offset) << (unsigned) getExtValue(Alignment);
+ else
+ CCEDiag(E->getArg(0),
+ diag::note_constexpr_baa_value_insufficient_alignment)
+ << Offset << (unsigned) getExtValue(Alignment);
+
+ return false;
+ }
+
+ return true;
+ }
default:
return ExprEvaluatorBaseTy::VisitCallExpr(E);
}
@@ -5166,7 +5370,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
if (ZeroInit && !ZeroInitialization(E))
return false;
- ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
+ auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
return HandleConstructorCall(E->getExprLoc(), This, Args,
cast<CXXConstructorDecl>(Definition), Info,
Result);
@@ -5270,6 +5474,9 @@ public:
bool VisitCallExpr(const CallExpr *E) {
return VisitConstructExpr(E);
}
+ bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E) {
+ return VisitConstructExpr(E);
+ }
};
} // end anonymous namespace
@@ -5645,7 +5852,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
return false;
}
- ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
+ auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
return HandleConstructorCall(E->getExprLoc(), Subobject, Args,
cast<CXXConstructorDecl>(Definition),
Info, *Value);
@@ -5786,8 +5993,6 @@ public:
bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
private:
- CharUnits GetAlignOfExpr(const Expr *E);
- CharUnits GetAlignOfType(QualType T);
static QualType GetObjectType(APValue::LValueBase B);
bool TryEvaluateBuiltinObjectSize(const CallExpr *E);
// FIXME: Missing: array subscript of vector, member of vector
@@ -5985,8 +6190,20 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E) {
return false;
}
- // If we can prove the base is null, lower to zero now.
- if (!Base.getLValueBase()) return Success(0, E);
+ if (!Base.getLValueBase()) {
+ // It is not possible to determine which objects ptr points to at compile time,
+ // __builtin_object_size should return (size_t) -1 for type 0 or 1
+ // and (size_t) 0 for type 2 or 3.
+ llvm::APSInt TypeIntVaue;
+ const Expr *ExprType = E->getArg(1);
+ if (!ExprType->EvaluateAsInt(TypeIntVaue, Info.Ctx))
+ return false;
+ if (TypeIntVaue == 0 || TypeIntVaue == 1)
+ return Success(-1, E);
+ if (TypeIntVaue == 2 || TypeIntVaue == 3)
+ return Success(0, E);
+ return Error(E);
+ }
QualType T = GetObjectType(Base.getLValueBase());
if (T.isNull() ||
@@ -6286,6 +6503,27 @@ static bool HasSameBase(const LValue &A, const LValue &B) {
A.getLValueCallIndex() == B.getLValueCallIndex();
}
+/// \brief Determine whether this is a pointer past the end of the complete
+/// object referred to by the lvalue.
+static bool isOnePastTheEndOfCompleteObject(const ASTContext &Ctx,
+ const LValue &LV) {
+ // A null pointer can be viewed as being "past the end" but we don't
+ // choose to look at it that way here.
+ if (!LV.getLValueBase())
+ return false;
+
+ // If the designator is valid and refers to a subobject, we're not pointing
+ // past the end.
+ if (!LV.getLValueDesignator().Invalid &&
+ !LV.getLValueDesignator().isOnePastTheEnd())
+ return false;
+
+ // We're a past-the-end pointer if we point to the byte after the object,
+ // no matter what our type or path is.
+ auto Size = Ctx.getTypeSizeInChars(getType(LV.getLValueBase()));
+ return LV.getLValueOffset() == Size;
+}
+
namespace {
/// \brief Data recursive integer evaluator of certain binary operators.
@@ -6605,15 +6843,27 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
QualType LHSTy = E->getLHS()->getType();
QualType RHSTy = E->getRHS()->getType();
- if (LHSTy->isAnyComplexType()) {
- assert(RHSTy->isAnyComplexType() && "Invalid comparison");
+ if (LHSTy->isAnyComplexType() || RHSTy->isAnyComplexType()) {
ComplexValue LHS, RHS;
-
- bool LHSOK = EvaluateComplex(E->getLHS(), LHS, Info);
+ bool LHSOK;
+ if (E->getLHS()->getType()->isRealFloatingType()) {
+ LHSOK = EvaluateFloat(E->getLHS(), LHS.FloatReal, Info);
+ if (LHSOK) {
+ LHS.makeComplexFloat();
+ LHS.FloatImag = APFloat(LHS.FloatReal.getSemantics());
+ }
+ } else {
+ LHSOK = EvaluateComplex(E->getLHS(), LHS, Info);
+ }
if (!LHSOK && !Info.keepEvaluatingAfterFailure())
return false;
- if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK)
+ if (E->getRHS()->getType()->isRealFloatingType()) {
+ if (!EvaluateFloat(E->getRHS(), RHS.FloatReal, Info) || !LHSOK)
+ return false;
+ RHS.makeComplexFloat();
+ RHS.FloatImag = APFloat(RHS.FloatReal.getSemantics());
+ } else if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK)
return false;
if (LHS.isComplexFloat()) {
@@ -6736,6 +6986,18 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
// object.
if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue))
return Error(E);
+ // We can't compare the address of the start of one object with the
+ // past-the-end address of another object, per C++ DR1652.
+ if ((LHSValue.Base && LHSValue.Offset.isZero() &&
+ isOnePastTheEndOfCompleteObject(Info.Ctx, RHSValue)) ||
+ (RHSValue.Base && RHSValue.Offset.isZero() &&
+ isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue)))
+ return Error(E);
+ // We can't tell whether an object is at the same address as another
+ // zero sized object.
+ if ((RHSValue.Base && isZeroSized(LHSValue)) ||
+ (LHSValue.Base && isZeroSized(RHSValue)))
+ return Error(E);
// Pointers with different bases cannot represent the same object.
// (Note that clang defaults to -fmerge-all-constants, which can
// lead to inconsistent results for comparisons involving the address
@@ -6940,39 +7202,6 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
}
-CharUnits IntExprEvaluator::GetAlignOfType(QualType T) {
- // C++ [expr.alignof]p3:
- // When alignof is applied to a reference type, the result is the
- // alignment of the referenced type.
- if (const ReferenceType *Ref = T->getAs<ReferenceType>())
- T = Ref->getPointeeType();
-
- // __alignof is defined to return the preferred alignment.
- return Info.Ctx.toCharUnitsFromBits(
- Info.Ctx.getPreferredTypeAlign(T.getTypePtr()));
-}
-
-CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) {
- E = E->IgnoreParens();
-
- // The kinds of expressions that we have special-case logic here for
- // should be kept up to date with the special checks for those
- // expressions in Sema.
-
- // alignof decl is always accepted, even if it doesn't make sense: we default
- // to 1 in those cases.
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- return Info.Ctx.getDeclAlign(DRE->getDecl(),
- /*RefAsPointee*/true);
-
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
- return Info.Ctx.getDeclAlign(ME->getMemberDecl(),
- /*RefAsPointee*/true);
-
- return GetAlignOfType(E->getType());
-}
-
-
/// VisitUnaryExprOrTypeTraitExpr - Evaluate a sizeof, alignof or vec_step with
/// a result as the expression's type.
bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
@@ -6980,9 +7209,9 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
switch(E->getKind()) {
case UETT_AlignOf: {
if (E->isArgumentType())
- return Success(GetAlignOfType(E->getArgumentType()), E);
+ return Success(GetAlignOfType(Info, E->getArgumentType()), E);
else
- return Success(GetAlignOfExpr(E->getArgumentExpr()), E);
+ return Success(GetAlignOfExpr(Info, E->getArgumentExpr()), E);
}
case UETT_VecStep: {
@@ -7732,24 +7961,49 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (E->isPtrMemOp() || E->isAssignmentOp() || E->getOpcode() == BO_Comma)
return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
- bool LHSOK = Visit(E->getLHS());
+ // Track whether the LHS or RHS is real at the type system level. When this is
+ // the case we can simplify our evaluation strategy.
+ bool LHSReal = false, RHSReal = false;
+
+ bool LHSOK;
+ if (E->getLHS()->getType()->isRealFloatingType()) {
+ LHSReal = true;
+ APFloat &Real = Result.FloatReal;
+ LHSOK = EvaluateFloat(E->getLHS(), Real, Info);
+ if (LHSOK) {
+ Result.makeComplexFloat();
+ Result.FloatImag = APFloat(Real.getSemantics());
+ }
+ } else {
+ LHSOK = Visit(E->getLHS());
+ }
if (!LHSOK && !Info.keepEvaluatingAfterFailure())
return false;
ComplexValue RHS;
- if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK)
+ if (E->getRHS()->getType()->isRealFloatingType()) {
+ RHSReal = true;
+ APFloat &Real = RHS.FloatReal;
+ if (!EvaluateFloat(E->getRHS(), Real, Info) || !LHSOK)
+ return false;
+ RHS.makeComplexFloat();
+ RHS.FloatImag = APFloat(Real.getSemantics());
+ } else if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK)
return false;
- assert(Result.isComplexFloat() == RHS.isComplexFloat() &&
- "Invalid operands to binary operator.");
+ assert(!(LHSReal && RHSReal) &&
+ "Cannot have both operands of a complex operation be real.");
switch (E->getOpcode()) {
default: return Error(E);
case BO_Add:
if (Result.isComplexFloat()) {
Result.getComplexFloatReal().add(RHS.getComplexFloatReal(),
APFloat::rmNearestTiesToEven);
- Result.getComplexFloatImag().add(RHS.getComplexFloatImag(),
- APFloat::rmNearestTiesToEven);
+ if (LHSReal)
+ Result.getComplexFloatImag() = RHS.getComplexFloatImag();
+ else if (!RHSReal)
+ Result.getComplexFloatImag().add(RHS.getComplexFloatImag(),
+ APFloat::rmNearestTiesToEven);
} else {
Result.getComplexIntReal() += RHS.getComplexIntReal();
Result.getComplexIntImag() += RHS.getComplexIntImag();
@@ -7759,8 +8013,13 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (Result.isComplexFloat()) {
Result.getComplexFloatReal().subtract(RHS.getComplexFloatReal(),
APFloat::rmNearestTiesToEven);
- Result.getComplexFloatImag().subtract(RHS.getComplexFloatImag(),
- APFloat::rmNearestTiesToEven);
+ if (LHSReal) {
+ Result.getComplexFloatImag() = RHS.getComplexFloatImag();
+ Result.getComplexFloatImag().changeSign();
+ } else if (!RHSReal) {
+ Result.getComplexFloatImag().subtract(RHS.getComplexFloatImag(),
+ APFloat::rmNearestTiesToEven);
+ }
} else {
Result.getComplexIntReal() -= RHS.getComplexIntReal();
Result.getComplexIntImag() -= RHS.getComplexIntImag();
@@ -7768,25 +8027,75 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
break;
case BO_Mul:
if (Result.isComplexFloat()) {
+ // This is an implementation of complex multiplication according to the
+ // constraints laid out in C11 Annex G. The implemantion uses the
+ // following naming scheme:
+ // (a + ib) * (c + id)
ComplexValue LHS = Result;
- APFloat &LHS_r = LHS.getComplexFloatReal();
- APFloat &LHS_i = LHS.getComplexFloatImag();
- APFloat &RHS_r = RHS.getComplexFloatReal();
- APFloat &RHS_i = RHS.getComplexFloatImag();
-
- APFloat Tmp = LHS_r;
- Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven);
- Result.getComplexFloatReal() = Tmp;
- Tmp = LHS_i;
- Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven);
- Result.getComplexFloatReal().subtract(Tmp, APFloat::rmNearestTiesToEven);
-
- Tmp = LHS_r;
- Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven);
- Result.getComplexFloatImag() = Tmp;
- Tmp = LHS_i;
- Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven);
- Result.getComplexFloatImag().add(Tmp, APFloat::rmNearestTiesToEven);
+ APFloat &A = LHS.getComplexFloatReal();
+ APFloat &B = LHS.getComplexFloatImag();
+ APFloat &C = RHS.getComplexFloatReal();
+ APFloat &D = RHS.getComplexFloatImag();
+ APFloat &ResR = Result.getComplexFloatReal();
+ APFloat &ResI = Result.getComplexFloatImag();
+ if (LHSReal) {
+ assert(!RHSReal && "Cannot have two real operands for a complex op!");
+ ResR = A * C;
+ ResI = A * D;
+ } else if (RHSReal) {
+ ResR = C * A;
+ ResI = C * B;
+ } else {
+ // In the fully general case, we need to handle NaNs and infinities
+ // robustly.
+ APFloat AC = A * C;
+ APFloat BD = B * D;
+ APFloat AD = A * D;
+ APFloat BC = B * C;
+ ResR = AC - BD;
+ ResI = AD + BC;
+ if (ResR.isNaN() && ResI.isNaN()) {
+ bool Recalc = false;
+ if (A.isInfinity() || B.isInfinity()) {
+ A = APFloat::copySign(
+ APFloat(A.getSemantics(), A.isInfinity() ? 1 : 0), A);
+ B = APFloat::copySign(
+ APFloat(B.getSemantics(), B.isInfinity() ? 1 : 0), B);
+ if (C.isNaN())
+ C = APFloat::copySign(APFloat(C.getSemantics()), C);
+ if (D.isNaN())
+ D = APFloat::copySign(APFloat(D.getSemantics()), D);
+ Recalc = true;
+ }
+ if (C.isInfinity() || D.isInfinity()) {
+ C = APFloat::copySign(
+ APFloat(C.getSemantics(), C.isInfinity() ? 1 : 0), C);
+ D = APFloat::copySign(
+ APFloat(D.getSemantics(), D.isInfinity() ? 1 : 0), D);
+ if (A.isNaN())
+ A = APFloat::copySign(APFloat(A.getSemantics()), A);
+ if (B.isNaN())
+ B = APFloat::copySign(APFloat(B.getSemantics()), B);
+ Recalc = true;
+ }
+ if (!Recalc && (AC.isInfinity() || BD.isInfinity() ||
+ AD.isInfinity() || BC.isInfinity())) {
+ if (A.isNaN())
+ A = APFloat::copySign(APFloat(A.getSemantics()), A);
+ if (B.isNaN())
+ B = APFloat::copySign(APFloat(B.getSemantics()), B);
+ if (C.isNaN())
+ C = APFloat::copySign(APFloat(C.getSemantics()), C);
+ if (D.isNaN())
+ D = APFloat::copySign(APFloat(D.getSemantics()), D);
+ Recalc = true;
+ }
+ if (Recalc) {
+ ResR = APFloat::getInf(A.getSemantics()) * (A * C - B * D);
+ ResI = APFloat::getInf(A.getSemantics()) * (A * D + B * C);
+ }
+ }
+ }
} else {
ComplexValue LHS = Result;
Result.getComplexIntReal() =
@@ -7799,33 +8108,57 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
break;
case BO_Div:
if (Result.isComplexFloat()) {
+ // This is an implementation of complex division according to the
+ // constraints laid out in C11 Annex G. The implemantion uses the
+ // following naming scheme:
+ // (a + ib) / (c + id)
ComplexValue LHS = Result;
- APFloat &LHS_r = LHS.getComplexFloatReal();
- APFloat &LHS_i = LHS.getComplexFloatImag();
- APFloat &RHS_r = RHS.getComplexFloatReal();
- APFloat &RHS_i = RHS.getComplexFloatImag();
- APFloat &Res_r = Result.getComplexFloatReal();
- APFloat &Res_i = Result.getComplexFloatImag();
-
- APFloat Den = RHS_r;
- Den.multiply(RHS_r, APFloat::rmNearestTiesToEven);
- APFloat Tmp = RHS_i;
- Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven);
- Den.add(Tmp, APFloat::rmNearestTiesToEven);
-
- Res_r = LHS_r;
- Res_r.multiply(RHS_r, APFloat::rmNearestTiesToEven);
- Tmp = LHS_i;
- Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven);
- Res_r.add(Tmp, APFloat::rmNearestTiesToEven);
- Res_r.divide(Den, APFloat::rmNearestTiesToEven);
-
- Res_i = LHS_i;
- Res_i.multiply(RHS_r, APFloat::rmNearestTiesToEven);
- Tmp = LHS_r;
- Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven);
- Res_i.subtract(Tmp, APFloat::rmNearestTiesToEven);
- Res_i.divide(Den, APFloat::rmNearestTiesToEven);
+ APFloat &A = LHS.getComplexFloatReal();
+ APFloat &B = LHS.getComplexFloatImag();
+ APFloat &C = RHS.getComplexFloatReal();
+ APFloat &D = RHS.getComplexFloatImag();
+ APFloat &ResR = Result.getComplexFloatReal();
+ APFloat &ResI = Result.getComplexFloatImag();
+ if (RHSReal) {
+ ResR = A / C;
+ ResI = B / C;
+ } else {
+ if (LHSReal) {
+ // No real optimizations we can do here, stub out with zero.
+ B = APFloat::getZero(A.getSemantics());
+ }
+ int DenomLogB = 0;
+ APFloat MaxCD = maxnum(abs(C), abs(D));
+ if (MaxCD.isFinite()) {
+ DenomLogB = ilogb(MaxCD);
+ C = scalbn(C, -DenomLogB);
+ D = scalbn(D, -DenomLogB);
+ }
+ APFloat Denom = C * C + D * D;
+ ResR = scalbn((A * C + B * D) / Denom, -DenomLogB);
+ ResI = scalbn((B * C - A * D) / Denom, -DenomLogB);
+ if (ResR.isNaN() && ResI.isNaN()) {
+ if (Denom.isPosZero() && (!A.isNaN() || !B.isNaN())) {
+ ResR = APFloat::getInf(ResR.getSemantics(), C.isNegative()) * A;
+ ResI = APFloat::getInf(ResR.getSemantics(), C.isNegative()) * B;
+ } else if ((A.isInfinity() || B.isInfinity()) && C.isFinite() &&
+ D.isFinite()) {
+ A = APFloat::copySign(
+ APFloat(A.getSemantics(), A.isInfinity() ? 1 : 0), A);
+ B = APFloat::copySign(
+ APFloat(B.getSemantics(), B.isInfinity() ? 1 : 0), B);
+ ResR = APFloat::getInf(ResR.getSemantics()) * (A * C + B * D);
+ ResI = APFloat::getInf(ResI.getSemantics()) * (B * C - A * D);
+ } else if (MaxCD.isInfinity() && A.isFinite() && B.isFinite()) {
+ C = APFloat::copySign(
+ APFloat(C.getSemantics(), C.isInfinity() ? 1 : 0), C);
+ D = APFloat::copySign(
+ APFloat(D.getSemantics(), D.isInfinity() ? 1 : 0), D);
+ ResR = APFloat::getZero(ResR.getSemantics()) * (A * C + B * D);
+ ResI = APFloat::getZero(ResI.getSemantics()) * (B * C - A * D);
+ }
+ }
+ }
} else {
if (RHS.getComplexIntReal() == 0 && RHS.getComplexIntImag() == 0)
return Error(E, diag::note_expr_divide_by_zero);
@@ -7966,6 +8299,7 @@ public:
default:
return ExprEvaluatorBaseTy::VisitCallExpr(E);
case Builtin::BI__assume:
+ case Builtin::BI__builtin_assume:
// The argument is not evaluated!
return true;
}
@@ -8338,6 +8672,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::CXXDeleteExprClass:
case Expr::CXXPseudoDestructorExprClass:
case Expr::UnresolvedLookupExprClass:
+ case Expr::TypoExprClass:
case Expr::DependentScopeDeclRefExprClass:
case Expr::CXXConstructExprClass:
case Expr::CXXStdInitializerListExprClass:
@@ -8373,6 +8708,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::PseudoObjectExprClass:
case Expr::AtomicExprClass:
case Expr::LambdaExprClass:
+ case Expr::CXXFoldExprClass:
return ICEDiag(IK_NotICE, E->getLocStart());
case Expr::InitListExprClass: {
@@ -8682,7 +9018,11 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx,
if (!E->isCXX11ConstantExpr(Ctx, &Result, Loc))
return false;
- assert(Result.isInt() && "pointer cast to int is not an ICE");
+ if (!Result.isInt()) {
+ if (Loc) *Loc = E->getExprLoc();
+ return false;
+ }
+
if (Value) *Value = Result.getInt();
return true;
}
@@ -8751,7 +9091,8 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
ArgVector ArgValues(Args.size());
for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
I != E; ++I) {
- if (!Evaluate(ArgValues[I - Args.begin()], Info, *I))
+ if ((*I)->isValueDependent() ||
+ !Evaluate(ArgValues[I - Args.begin()], Info, *I))
// If evaluation fails, throw away the argument entirely.
ArgValues[I - Args.begin()] = APValue();
if (Info.EvalStatus.HasSideEffects)