Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -661,6 +661,10 @@ /// CurrentCall - The top of the constexpr call stack. CallStackFrame *CurrentCall; + /// ArgumentCallStack - Used to store Arguments to function calls + /// only required if diagnostics should produce a callstack + SmallVectorImpl *ArgumentCallStack; + /// CallStackDepth - The number of calls in the call stack right now. unsigned CallStackDepth; @@ -789,14 +793,14 @@ bool checkingForOverflow() { return EvalMode == EM_EvaluateForOverflow; } EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode) - : Ctx(const_cast(C)), EvalStatus(S), CurrentCall(nullptr), - CallStackDepth(0), NextCallIndex(1), - StepsLeft(getLangOpts().ConstexprStepLimit), - BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr), - EvaluatingDecl((const ValueDecl *)nullptr), - EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false), - HasFoldFailureDiagnostic(false), IsSpeculativelyEvaluating(false), - InConstantContext(false), EvalMode(Mode) {} + : Ctx(const_cast(C)), EvalStatus(S), CurrentCall(nullptr), + ArgumentCallStack(nullptr), CallStackDepth(0), NextCallIndex(1), + StepsLeft(getLangOpts().ConstexprStepLimit), + BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr), + EvaluatingDecl((const ValueDecl *)nullptr), + EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false), + HasFoldFailureDiagnostic(false), IsSpeculativelyEvaluating(false), + InConstantContext(false), EvalMode(Mode) {} void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) { EvaluatingDecl = Base; @@ -1240,10 +1244,20 @@ Arguments(Arguments), CallLoc(CallLoc), Index(Info.NextCallIndex++) { Info.CurrentCall = this; ++Info.CallStackDepth; + if (Info.ArgumentCallStack) { + Info.ArgumentCallStack->reserve(Info.ArgumentCallStack->size() + + Callee->param_size()); + std::copy(Arguments, Arguments + Callee->param_size(), + std::back_inserter(*Info.ArgumentCallStack)); + } } CallStackFrame::~CallStackFrame() { assert(Info.CurrentCall == this && "calls retired out of order"); + if (Info.ArgumentCallStack && Caller) { + Info.ArgumentCallStack->resize(Info.ArgumentCallStack->size() - + Callee->param_size()); + } --Info.CallStackDepth; Info.CurrentCall = Caller; } @@ -1257,9 +1271,12 @@ return Result; } -static void describeCall(CallStackFrame *Frame, raw_ostream &Out); +static void describeCall(CallStackFrame *Frame, raw_ostream &Out, + SmallVectorImpl *ArgumentCallStack, + unsigned Pos); void EvalInfo::addCallStack(unsigned Limit) { + assert(ArgumentCallStack && "needed to produce a call stack"); // Determine which calls to skip, if any. unsigned ActiveCalls = CallStackDepth - 1; unsigned SkipStart = ActiveCalls, SkipEnd = SkipStart; @@ -1270,8 +1287,10 @@ // Walk the call stack and add the diagnostics. unsigned CallIdx = 0; + unsigned Pos = ArgumentCallStack->size(); for (CallStackFrame *Frame = CurrentCall; Frame != &BottomFrame; Frame = Frame->Caller, ++CallIdx) { + Pos -= Frame->Callee->param_size(); // Skip this call? if (CallIdx >= SkipStart && CallIdx < SkipEnd) { if (CallIdx == SkipStart) { @@ -1294,7 +1313,7 @@ SmallVector Buffer; llvm::raw_svector_ostream Out(Buffer); - describeCall(Frame, Out); + describeCall(Frame, Out, ArgumentCallStack, Pos); addDiag(Frame->CallLoc, diag::note_constexpr_call_here) << Out.str(); } } @@ -1654,7 +1673,9 @@ } /// Produce a string describing the given constexpr call. -static void describeCall(CallStackFrame *Frame, raw_ostream &Out) { +static void describeCall(CallStackFrame *Frame, raw_ostream &Out, + SmallVectorImpl *ArgumentCallStack, + unsigned Pos) { unsigned ArgIndex = 0; bool IsMemberCall = isa(Frame->Callee) && !isa(Frame->Callee) && @@ -1679,7 +1700,7 @@ Out << ", "; const ParmVarDecl *Param = *I; - const APValue &Arg = Frame->Arguments[ArgIndex]; + const APValue &Arg = (*ArgumentCallStack)[Pos + ArgIndex]; Arg.printPretty(Out, Frame->Info.Ctx, Param->getType()); if (ArgIndex == 0 && IsMemberCall) @@ -11076,6 +11097,8 @@ bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx, bool InConstantContext) const { EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); + SmallVector ArgumentCallStack; + Info.ArgumentCallStack = &ArgumentCallStack; Info.InConstantContext = InConstantContext; return ::EvaluateAsRValue(this, Result, Ctx, Info); } @@ -11115,7 +11138,6 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold); - LValue LV; if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects || !CheckLValueConstantExpression(Info, getExprLoc(), @@ -11131,6 +11153,8 @@ const ASTContext &Ctx) const { EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression; EvalInfo Info(Ctx, Result, EM); + SmallVector ArgumentCallStack; + Info.ArgumentCallStack = &ArgumentCallStack; Info.InConstantContext = true; if (!::Evaluate(Result.Val, Info, this)) return false; @@ -11156,7 +11180,8 @@ : EvalInfo::EM_ConstantFold); InitInfo.setEvaluatingDecl(VD, Value); InitInfo.InConstantContext = true; - + SmallVector ArgumentCallStack; + InitInfo.ArgumentCallStack = &ArgumentCallStack; LValue LVal; LVal.set(VD); @@ -11751,6 +11776,8 @@ SmallVector Diags; Status.Diag = &Diags; EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression); + SmallVector ArgumentCallStack; + Info.ArgumentCallStack = &ArgumentCallStack; APValue Scratch; bool IsConstExpr = ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch); Index: clang/test/SemaCXX/constant-expression-cxx1y.cpp =================================================================== --- clang/test/SemaCXX/constant-expression-cxx1y.cpp +++ clang/test/SemaCXX/constant-expression-cxx1y.cpp @@ -1159,3 +1159,32 @@ enum class InEnum3 { THREE = indirect_builtin_constant_p("abc") }; + +constexpr int f1(int i, int b) { + i += 4; + b -= 4; + // expected-note@+1 {{negative shift count -7}} + return i << b; +} + +constexpr int f2(int i) { + int b = 0; + i += 1; + b -= 1; + // expected-note@+1 {{in call to 'f1(3, -3)'}} + return f1(i + 2, b -= 2); +} + +constexpr int f(int i) { + i -= 1; + //expected-note@+1 {{negative shift count -1}} + return 1 << i; +} + +// expected-error@+2 {{constant expression}} +// expected-note@+1 {{in call to 'f2(0)'}} +constexpr int val = f2(0); + +// expected-error@+2 {{constant expression}} +// expected-note@+1 {{in call to 'f(0)'}} +static_assert(f(0), ""); \ No newline at end of file