diff options
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r-- | lib/AST/ExprConstant.cpp | 579 |
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) |