Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -2751,12 +2751,11 @@ /// /// \param Data Pointer data that will be provided to the callback function /// when it is called. - void AddDeallocation(void (*Callback)(void*), void *Data); + void AddDeallocation(void (*Callback)(void *), void *Data) const; /// If T isn't trivially destructible, calls AddDeallocation to register it /// for destruction. - template - void addDestruction(T *Ptr) { + template void addDestruction(T *Ptr) const { if (!std::is_trivially_destructible::value) { auto DestroyPtr = [](void *V) { static_cast(V)->~T(); }; AddDeallocation(DestroyPtr, Ptr); @@ -2819,10 +2818,6 @@ APValue *getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E, bool MayCreate); - /// Adds an APValue that will be destructed during the destruction of the - /// ASTContext. - void AddAPValueCleanup(APValue *Ptr) const { APValueCleanups.push_back(Ptr); } - /// Return a string representing the human readable name for the specified /// function declaration or file name. Used by SourceLocExpr and /// PredefinedExpr to cache evaluated results. @@ -2989,7 +2984,7 @@ // in order to track and run destructors while we're tearing things down. using DeallocationFunctionsAndArguments = llvm::SmallVector, 16>; - DeallocationFunctionsAndArguments Deallocations; + mutable DeallocationFunctionsAndArguments Deallocations; // FIXME: This currently contains the set of StoredDeclMaps used // by DeclContext objects. This probably should not be in ASTContext, Index: clang/include/clang/AST/Expr.h =================================================================== --- clang/include/clang/AST/Expr.h +++ clang/include/clang/AST/Expr.h @@ -998,6 +998,9 @@ EmptyShell Empty); static ResultStorageKind getStorageKind(const APValue &Value); + static ResultStorageKind getStorageKind(const Type *T, + const ASTContext &Context); + SourceLocation getBeginLoc() const LLVM_READONLY { return SubExpr->getBeginLoc(); } @@ -1009,24 +1012,20 @@ return T->getStmtClass() == ConstantExprClass; } - void SetResult(APValue Value) { MoveIntoResult(Value); } - void MoveIntoResult(APValue &Value); + void SetResult(APValue Value, const ASTContext &Context) { + MoveIntoResult(Value, Context); + } + void MoveIntoResult(APValue &Value, const ASTContext &Context); APValue::ValueKind getResultAPValueKind() const { - switch (ConstantExprBits.ResultKind) { - case ConstantExpr::RSK_APValue: - return APValueResult().getKind(); - case ConstantExpr::RSK_Int64: - return APValue::Int; - case ConstantExpr::RSK_None: - return APValue::None; - } - llvm_unreachable("invalid ResultKind"); + return static_cast(ConstantExprBits.APValueKind); } ResultStorageKind getResultStorageKind() const { return static_cast(ConstantExprBits.ResultKind); } APValue getAPValueResult() const; + const APValue &getResultAsAPValue() const { return APValueResult(); } + llvm::APSInt getResultAsAPSInt() const; // Iterators child_range children() { return child_range(&SubExpr, &SubExpr+1); } Index: clang/include/clang/AST/Stmt.h =================================================================== --- clang/include/clang/AST/Stmt.h +++ clang/include/clang/AST/Stmt.h @@ -332,6 +332,9 @@ /// The kind of result that is trail-allocated. unsigned ResultKind : 2; + /// Kind of Result as defined by APValue::Kind + unsigned APValueKind : 4; + /// When ResultKind == RSK_Int64. whether the trail-allocated integer is /// signed. unsigned IsUnsigned : 1; @@ -340,6 +343,10 @@ /// integer. 7 bits because it is the minimal number of bit to represent a /// value from 0 to 64 (the size of the trail-allocated number). unsigned BitWidth : 7; + + /// When ResultKind == RSK_APValue. Wether the ASTContext will cleanup the + /// destructor on the trail-allocated APValue. + unsigned HasCleanup : 1; }; class PredefinedExprBitfields { Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -10294,7 +10294,8 @@ /// Can optionally return the value of the expression. ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, VerifyICEDiagnoser &Diagnoser, - bool AllowFold = true); + bool AllowFold = true, + bool StoreResult = true); ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, unsigned DiagID, bool AllowFold = true); Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -908,7 +908,7 @@ Parents.reset(); } -void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) { +void ASTContext::AddDeallocation(void (*Callback)(void *), void *Data) const { Deallocations.push_back({Callback, Data}); } Index: clang/lib/AST/Expr.cpp =================================================================== --- clang/lib/AST/Expr.cpp +++ clang/lib/AST/Expr.cpp @@ -239,6 +239,7 @@ ConstantExpr::getStorageKind(const APValue &Value) { switch (Value.getKind()) { case APValue::None: + case APValue::Indeterminate: return ConstantExpr::RSK_None; case APValue::Int: if (!Value.getInt().needsCleanup()) @@ -249,9 +250,18 @@ } } +ConstantExpr::ResultStorageKind +ConstantExpr::getStorageKind(const Type *T, const ASTContext &Context) { + if (T->isIntegralOrEnumerationType() && Context.getTypeInfo(T).Width <= 64) + return ConstantExpr::RSK_Int64; + return ConstantExpr::RSK_APValue; +} + void ConstantExpr::DefaultInit(ResultStorageKind StorageKind) { ConstantExprBits.ResultKind = StorageKind; - if (StorageKind == RSK_APValue) + ConstantExprBits.APValueKind = APValue::None; + ConstantExprBits.HasCleanup = false; + if (StorageKind == ConstantExpr::RSK_APValue) ::new (getTrailingObjects()) APValue(); } @@ -269,8 +279,6 @@ StorageKind == ConstantExpr::RSK_Int64); void *Mem = Context.Allocate(Size, alignof(ConstantExpr)); ConstantExpr *Self = new (Mem) ConstantExpr(E, StorageKind); - if (StorageKind == ConstantExpr::RSK_APValue) - Context.AddAPValueCleanup(&Self->APValueResult()); return Self; } @@ -278,7 +286,7 @@ const APValue &Result) { ResultStorageKind StorageKind = getStorageKind(Result); ConstantExpr *Self = Create(Context, E, StorageKind); - Self->SetResult(Result); + Self->SetResult(Result, Context); return Self; } @@ -296,14 +304,13 @@ StorageKind == ConstantExpr::RSK_Int64); void *Mem = Context.Allocate(Size, alignof(ConstantExpr)); ConstantExpr *Self = new (Mem) ConstantExpr(StorageKind, Empty); - if (StorageKind == ConstantExpr::RSK_APValue) - Context.AddAPValueCleanup(&Self->APValueResult()); return Self; } -void ConstantExpr::MoveIntoResult(APValue &Value) { +void ConstantExpr::MoveIntoResult(APValue &Value, const ASTContext &Context) { assert(getStorageKind(Value) == ConstantExprBits.ResultKind && "Invalid storage for this value kind"); + ConstantExprBits.APValueKind = Value.getKind(); switch (ConstantExprBits.ResultKind) { case RSK_None: return; @@ -313,12 +320,28 @@ ConstantExprBits.IsUnsigned = Value.getInt().isUnsigned(); return; case RSK_APValue: + if (!ConstantExprBits.HasCleanup && Value.needsCleanup()) { + ConstantExprBits.HasCleanup = true; + Context.addDestruction(&APValueResult()); + } APValueResult() = std::move(Value); return; } llvm_unreachable("Invalid ResultKind Bits"); } +llvm::APSInt ConstantExpr::getResultAsAPSInt() const { + switch (ConstantExprBits.ResultKind) { + case ConstantExpr::RSK_APValue: + return APValueResult().getInt(); + case ConstantExpr::RSK_Int64: + return llvm::APSInt(llvm::APInt(ConstantExprBits.BitWidth, Int64Result()), + ConstantExprBits.IsUnsigned); + default: + llvm_unreachable("invalid Accessor"); + } +} + APValue ConstantExpr::getAPValueResult() const { switch (ConstantExprBits.ResultKind) { case ConstantExpr::RSK_APValue: Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -8963,6 +8963,8 @@ bool IntExprEvaluator::VisitConstantExpr(const ConstantExpr *E) { llvm::SaveAndRestore InConstantContext(Info.InConstantContext, true); + if (E->getResultStorageKind() != ConstantExpr::RSK_None) + return Success(E->getAPValueResult(), E); return ExprEvaluatorBaseTy::VisitConstantExpr(E); } Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -14006,8 +14006,6 @@ ExprResult Converted = PerformContextuallyConvertToBool(AssertExpr); if (Converted.isInvalid()) Failed = true; - else - Converted = ConstantExpr::Create(Context, Converted.get()); llvm::APSInt Cond; if (!Failed && VerifyIntegerConstantExpression(Converted.get(), &Cond, Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -14467,10 +14467,10 @@ S.Diag(Loc, diag::ext_expr_not_ice) << SR << S.LangOpts.CPlusPlus; } -ExprResult -Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, - VerifyICEDiagnoser &Diagnoser, - bool AllowFold) { +ExprResult Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, + VerifyICEDiagnoser &Diagnoser, + bool AllowFold, + bool StoreResult) { SourceLocation DiagLoc = E->getBeginLoc(); if (getLangOpts().CPlusPlus11) { @@ -14538,14 +14538,13 @@ return ExprError(); } - if (!isa(E)) - E = ConstantExpr::Create(Context, E); - // Circumvent ICE checking in C++11 to avoid evaluating the expression twice // in the non-ICE case. if (!getLangOpts().CPlusPlus11 && E->isIntegerConstantExpr(Context)) { if (Result) *Result = E->EvaluateKnownConstIntCheckOverflow(Context); + if (!isa(E)) + E = ConstantExpr::Create(Context, E); return E; } @@ -14555,8 +14554,13 @@ // Try to evaluate the expression, and produce diagnostics explaining why it's // not a constant expression as a side-effect. - bool Folded = E->EvaluateAsRValue(EvalResult, Context) && - EvalResult.Val.isInt() && !EvalResult.HasSideEffects; + bool Folded = + E->EvaluateAsRValue(EvalResult, Context, /*isConstantContext*/ true) && + EvalResult.Val.isInt() && !EvalResult.HasSideEffects; + + if (!isa(E)) + if (StoreResult) + E = ConstantExpr::Create(Context, E, EvalResult.Val); // In C++11, we can rely on diagnostics being produced for any expression // which is not a constant expression. If no diagnostics were produced, then Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -5514,7 +5514,12 @@ if (Notes.empty()) { // It's a constant expression. - return ConstantExpr::Create(S.Context, Result.get(), Value); + + // ExplicitBool wouldn't use the value stored in ConstantExpr. + if (CCE != Sema::CCEK_ExplicitBool) + return ConstantExpr::Create(S.Context, Result.get(), Value); + else + return ConstantExpr::Create(S.Context, Result.get()); } }