/// This - The binding for the this pointer in this call, if any.
const LValue *This;
+ /// CallExpr - The syntactical structure of member function calls
+ const Expr *CallExpr;
+
/// Information on how to find the arguments to this call. Our arguments
/// are stored in our parent's CallStackFrame, using the ParmVarDecl* as a
/// key and this value as the version.
CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
const FunctionDecl *Callee, const LValue *This,
- CallRef Arguments);
+ const Expr *CallExpr, CallRef Arguments);
~CallStackFrame();
// Return the temporary for Key whose version number is Version.
CallStackDepth(0), NextCallIndex(1),
StepsLeft(C.getLangOpts().ConstexprStepLimit),
EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp),
- BottomFrame(*this, SourceLocation(), nullptr, nullptr, CallRef()),
+ BottomFrame(*this, SourceLocation(), /*Callee=*/nullptr,
+ /*This=*/nullptr,
+ /*CallExpr=*/nullptr, CallRef()),
EvaluatingDecl((const ValueDecl *)nullptr),
EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
HasFoldFailureDiagnostic(false), EvalMode(Mode) {}
CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
const FunctionDecl *Callee, const LValue *This,
- CallRef Call)
+ const Expr *CallExpr, CallRef Call)
: Info(Info), Caller(Info.CurrentCall), Callee(Callee), This(This),
- Arguments(Call), CallLoc(CallLoc), Index(Info.NextCallIndex++) {
+ CallExpr(CallExpr), Arguments(Call), CallLoc(CallLoc),
+ Index(Info.NextCallIndex++) {
Info.CurrentCall = this;
++Info.CallStackDepth;
}
Out << *Callee << '(';
if (This && IsMemberCall) {
- APValue Val;
- This->moveInto(Val);
- Val.printPretty(Out, Info.Ctx,
- This->Designator.MostDerivedType);
- // FIXME: Add parens around Val if needed.
- Out << "->" << *Callee << '(';
+ if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(CallExpr)) {
+ const Expr *Object = MCE->getImplicitObjectArgument();
+ Object->printPretty(Out, /*Helper=*/nullptr, Info.Ctx.getPrintingPolicy(),
+ /*Indentation=*/0);
+ if (Object->getType()->isPointerType())
+ Out << "->";
+ else
+ Out << ".";
+ } else if (const auto *OCE =
+ dyn_cast_if_present<CXXOperatorCallExpr>(CallExpr)) {
+ OCE->getArg(0)->printPretty(Out, /*Helper=*/nullptr,
+ Info.Ctx.getPrintingPolicy(),
+ /*Indentation=*/0);
+ Out << ".";
+ } else {
+ APValue Val;
+ This->moveInto(Val);
+ Val.printPretty(
+ Out, Info.Ctx,
+ Info.Ctx.getLValueReferenceType(This->Designator.MostDerivedType));
+ Out << ".";
+ }
+ Out << *Callee << '(';
IsMemberCall = false;
}
/// Evaluate a function call.
static bool HandleFunctionCall(SourceLocation CallLoc,
const FunctionDecl *Callee, const LValue *This,
- ArrayRef<const Expr *> Args, CallRef Call,
- const Stmt *Body, EvalInfo &Info,
+ const Expr *E, ArrayRef<const Expr *> Args,
+ CallRef Call, const Stmt *Body, EvalInfo &Info,
APValue &Result, const LValue *ResultSlot) {
if (!Info.CheckCallLimit(CallLoc))
return false;
- CallStackFrame Frame(Info, CallLoc, Callee, This, Call);
+ CallStackFrame Frame(Info, CallLoc, Callee, This, E, Call);
// For a trivial copy or move assignment, perform an APValue copy. This is
// essential for unions, where the operations performed by the assignment
Info,
ObjectUnderConstruction{This.getLValueBase(), This.Designator.Entries},
RD->getNumBases());
- CallStackFrame Frame(Info, CallLoc, Definition, &This, Call);
+ CallStackFrame Frame(Info, CallLoc, Definition, &This, E, Call);
// FIXME: Creating an APValue just to hold a nonexistent return value is
// wasteful.
if (!CheckConstexprFunction(Info, CallLoc, DD, Definition, Body))
return false;
- CallStackFrame Frame(Info, CallLoc, Definition, &This, CallRef());
+ CallStackFrame Frame(Info, CallLoc, Definition, &This, /*CallExpr=*/nullptr,
+ CallRef());
// We're now in the period of destruction of this object.
unsigned BasesLeft = RD->getNumBases();
Stmt *Body = FD->getBody(Definition);
if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body) ||
- !HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Call,
+ !HandleFunctionCall(E->getExprLoc(), Definition, This, E, Args, Call,
Body, Info, Result, ResultSlot))
return false;
Info.EvalStatus.HasSideEffects = false;
// Build fake call to Callee.
- CallStackFrame Frame(Info, Callee->getLocation(), Callee, ThisPtr, Call);
+ CallStackFrame Frame(Info, Callee->getLocation(), Callee, ThisPtr, This,
+ Call);
// FIXME: Missing ExprWithCleanups in enable_if conditions?
FullExpressionRAII Scope(Info);
return Evaluate(Value, Info, this) && Scope.destroy() &&
} else {
SourceLocation Loc = FD->getLocation();
HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : nullptr,
- Args, CallRef(), FD->getBody(), Info, Scratch, nullptr);
+ &VIE, Args, CallRef(), FD->getBody(), Info, Scratch,
+ /*ResultSlot=*/nullptr);
}
return Diags.empty();
Info.CheckingPotentialConstantExpression = true;
// Fabricate a call stack frame to give the arguments a plausible cover story.
- CallStackFrame Frame(Info, SourceLocation(), FD, /*This*/ nullptr, CallRef());
+ CallStackFrame Frame(Info, SourceLocation(), FD, /*This=*/nullptr,
+ /*CallExpr=*/nullptr, CallRef());
APValue ResultScratch;
Evaluate(ResultScratch, Info, E);
int n;
};
constexpr int S::f() const {
- return static_cast<const T*>(this)->n; // expected-note {{cannot cast}}
+ return static_cast<const T*>(this)->n; // expected-note 5{{cannot cast}}
}
constexpr int S::g() const {
// FIXME: Better diagnostic for this.
// The T temporary is implicitly cast to an S subobject, but we can recover the
// T full-object via a base-to-derived cast, or a derived-to-base-casted member
// pointer.
-static_assert(S().f(), ""); // expected-error {{constant expression}} expected-note {{in call to '&S()->f()'}}
-static_assert(S().g(), ""); // expected-error {{constant expression}} expected-note {{in call to '&S()->g()'}}
+static_assert(S().f(), ""); // expected-error {{constant expression}} expected-note {{in call to 'S().f()'}}
+static_assert(S().g(), ""); // expected-error {{constant expression}} expected-note {{in call to 'S().g()'}}
+constexpr S sobj;
+constexpr const S& slref = sobj;
+constexpr const S&& srref = S();
+constexpr const S *sptr = &sobj;
+static_assert(sobj.f(), ""); // expected-error {{constant expression}} \
+ expected-note {{in call to 'sobj.f()'}}
+static_assert(sptr->f(), ""); // expected-error {{constant expression}} \
+ expected-note {{in call to 'sptr->f()'}}
+static_assert(slref.f(), ""); // expected-error {{constant expression}} \
+ expected-note {{in call to 'slref.f()'}}
+static_assert(srref.f(), ""); // expected-error {{constant expression}} \
+ expected-note {{in call to 'srref.f()'}}
static_assert(T(3).f() == 3, "");
static_assert(T(4).g() == 4, "");