hazohelet updated this revision to Diff 533964. hazohelet added a comment. Address review comment NFC
- make some arguments conform to bugprone-argument-comments - edit release note text CHANGES SINCE LAST ACTION https://reviews.llvm.org/D151720/new/ https://reviews.llvm.org/D151720 Files: clang/docs/ReleaseNotes.rst clang/lib/AST/ExprConstant.cpp clang/test/AST/Interp/constexpr-nqueens.cpp clang/test/AST/Interp/lambda.cpp clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp clang/test/CXX/temp/temp.param/p8-cxx20.cpp clang/test/SemaCXX/constant-expression-cxx11.cpp clang/test/SemaCXX/constexpr-frame-describe.cpp clang/test/SemaCXX/cxx2a-consteval.cpp clang/test/SemaCXX/deduced-return-type-cxx14.cpp
Index: clang/test/SemaCXX/deduced-return-type-cxx14.cpp =================================================================== --- clang/test/SemaCXX/deduced-return-type-cxx14.cpp +++ clang/test/SemaCXX/deduced-return-type-cxx14.cpp @@ -296,7 +296,7 @@ void f() { X<int>().f(); Y<void>().f(); - constexpr int q = Y<int>().f(); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to '&Y<int>()->f()'}} + constexpr int q = Y<int>().f(); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'Y<int>().f()'}} } struct NonLiteral { ~NonLiteral(); } nl; // cxx14-note {{user-provided destructor}} // cxx20_23-note@-1 {{'NonLiteral' is not literal because its destructor is not constexpr}} Index: clang/test/SemaCXX/cxx2a-consteval.cpp =================================================================== --- clang/test/SemaCXX/cxx2a-consteval.cpp +++ clang/test/SemaCXX/cxx2a-consteval.cpp @@ -840,13 +840,13 @@ copy<foo> fail1{good0}; // expected-error {{call to consteval function 'defaulted_special_member_template::copy<defaulted_special_member_template::foo>::copy' is not a constant expression}} \ expected-note {{in call to 'copy(good0)'}} fail1 = good0; // expected-error {{call to consteval function 'defaulted_special_member_template::copy<defaulted_special_member_template::foo>::operator=' is not a constant expression}} \ - expected-note {{in call to '&fail1->operator=(good0)'}} + expected-note {{in call to 'fail1.operator=(good0)'}} move<foo> good1; move<foo> fail2{static_cast<move<foo>&&>(good1)}; // expected-error {{call to consteval function 'defaulted_special_member_template::move<defaulted_special_member_template::foo>::move' is not a constant expression}} \ expected-note {{in call to 'move(good1)'}} fail2 = static_cast<move<foo>&&>(good1); // expected-error {{call to consteval function 'defaulted_special_member_template::move<defaulted_special_member_template::foo>::operator=' is not a constant expression}} \ - expected-note {{in call to '&fail2->operator=(good1)'}} + expected-note {{in call to 'fail2.operator=(good1)'}} } } // namespace defaulted_special_member_template Index: clang/test/SemaCXX/constexpr-frame-describe.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/constexpr-frame-describe.cpp @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s + + +struct Foo { + constexpr void zomg() const { (void)(1 / 0); } // expected-error {{constant expression}} \ + expected-warning {{division by zero}} \ + expected-note 2{{division by zero}} +}; + +struct S { + constexpr S() {} + constexpr bool operator==(const S&) const { // expected-error {{never produces a constant expression}} + return 1 / 0; // expected-warning {{division by zero}} \ + expected-note 3{{division by zero}} + } + + constexpr bool heh() const { + auto F = new Foo(); + F->zomg(); // expected-note {{in call to 'F->zomg()'}} + delete F; + return false; + } +}; + +constexpr S s; + +static_assert(s.heh()); // expected-error {{constant expression}} \ + expected-note {{in call to 's.heh()'}} + +constexpr S s2; +constexpr const S *sptr = &s; +constexpr const S *sptr2 = &s2; +static_assert(s == s2); // expected-error {{constant expression}} \ + expected-note {{in call to 's.operator==(s2)'}} +static_assert(*sptr == *sptr2); // expected-error {{constant expression}} \ + expected-note {{in call to '*sptr.operator==(s2)'}} + +struct A { + constexpr int foo() { (void)(1/0); return 1;} // expected-error {{never produces a constant expression}} \ + expected-warning {{division by zero}} \ + expected-note 2{{division by zero}} +}; + +struct B { + A aa; + A *a = &aa; +}; + +struct C { + B b; +}; + +struct D { + C cc; + C *c = &cc; +}; + +constexpr D d{}; +static_assert(d.c->b.a->foo() == 1); // expected-error {{constant expression}} \ + expected-note {{in call to 'd.c->b.a->foo()'}} Index: clang/test/SemaCXX/constant-expression-cxx11.cpp =================================================================== --- clang/test/SemaCXX/constant-expression-cxx11.cpp +++ clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -975,7 +975,7 @@ 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. @@ -984,8 +984,20 @@ // 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, ""); Index: clang/test/CXX/temp/temp.param/p8-cxx20.cpp =================================================================== --- clang/test/CXX/temp/temp.param/p8-cxx20.cpp +++ clang/test/CXX/temp/temp.param/p8-cxx20.cpp @@ -61,5 +61,5 @@ template<D d> struct Z {}; Z<D{2, true}> z1; - Z<D{2, false}> z2; // expected-error {{non-type template argument is not a constant expression}} expected-note-re {{in call to '{{.*}}->~D()'}} + Z<D{2, false}> z2; // expected-error {{non-type template argument is not a constant expression}} expected-note-re {{in call to '{{.*}}.~D()'}} } Index: clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp =================================================================== --- clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp +++ clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp @@ -42,12 +42,30 @@ bool ok; constexpr A(bool ok) : ok(ok) {} constexpr ~A() noexcept(false) { - void oops(); // expected-note 2{{declared here}} - if (!ok) oops(); // expected-note 2{{non-constexpr function}} + void oops(); // expected-note 6{{declared here}} + if (!ok) oops(); // expected-note 6{{non-constexpr function}} } }; +struct B { + A a[2]; + constexpr B(bool ok) : a{A(!ok), A(ok)}{} +}; + +struct Cons { + bool val[2]; + constexpr Cons() : val{true, false} {} +}; + constexpr A const_dtor(true); +static_assert(B(false).a[1].ok); // expected-error {{static assertion expression is not an integral constant expression}} \ + expected-note {{in call to 'B(false).a[1].~A()'}} expected-note {{in call to 'B(false).~B()'}} +static_assert(B(true).a[1].ok); // expected-error {{static assertion expression is not an integral constant expression}} \ + expected-note {{in call to 'B(true).a[0].~A()'}} expected-note {{in call to 'B(true).~B()'}} +static_assert(B(Cons().val[1]).a[1].ok); // expected-error {{static assertion expression is not an integral constant expression}} \ + expected-note {{in call to 'B(Cons().val[1]).a[1].~A()'}} expected-note {{in call to 'B(Cons().val[1]).~B()'}} +static_assert(B((new Cons)->val[0]).a[1].ok); // expected-error {{static assertion expression is not an integral constant expression}} \ + expected-note {{in call to 'B((new Cons)->val[0]).a[0].~A()'}} expected-note {{in call to 'B((new Cons)->val[0]).~B()'}} constexpr A non_const_dtor(false); // expected-error {{must have constant destruction}} expected-note {{in call}} -constexpr A arr_dtor[5] = {true, true, true, false, true}; // expected-error {{must have constant destruction}} expected-note {{in call to '&arr_dtor[3]->~A()'}} +constexpr A arr_dtor[5] = {true, true, true, false, true}; // expected-error {{must have constant destruction}} expected-note {{in call to 'arr_dtor[3].~A()'}} #endif Index: clang/test/AST/Interp/lambda.cpp =================================================================== --- clang/test/AST/Interp/lambda.cpp +++ clang/test/AST/Interp/lambda.cpp @@ -48,7 +48,7 @@ }; return f(); // expected-note {{in call to '&f->operator()()'}} \ - // ref-note {{in call to '&f->operator()()'}} + // ref-note {{in call to 'f.operator()()'}} } static_assert(div(8, 2) == 4); static_assert(div(8, 0) == 4); // expected-error {{not an integral constant expression}} \ Index: clang/test/AST/Interp/constexpr-nqueens.cpp =================================================================== --- clang/test/AST/Interp/constexpr-nqueens.cpp +++ clang/test/AST/Interp/constexpr-nqueens.cpp @@ -48,7 +48,7 @@ constexpr Board buildBoardScan(int N, int Col, int Row, const Board &B) { return Row == N ? Board(0, true) : B.ok(Row, Col) ? - tryBoard(buildBoardRecurse(N, Col + 1, B.addQueen(Row, Col)), // ref-note {{in call to '&Board()->addQueen(0, 0)}} \ + tryBoard(buildBoardRecurse(N, Col + 1, B.addQueen(Row, Col)), // ref-note {{in call to 'B.addQueen(0, 0)}} \ // expected-note {{in call to '&Board()->addQueen(0, 0)}} N, Col, Row+1, B) : buildBoardScan(N, Col, Row + 1, B); Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -530,6 +530,9 @@ /// 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. @@ -583,7 +586,7 @@ 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. @@ -977,7 +980,9 @@ 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) {} @@ -1435,9 +1440,10 @@ 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; } @@ -1917,12 +1923,29 @@ 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; } @@ -6160,13 +6183,13 @@ /// 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 @@ -6231,7 +6254,7 @@ 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. @@ -6532,7 +6555,8 @@ 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(); @@ -7801,7 +7825,7 @@ 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; @@ -16195,7 +16219,8 @@ 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() && @@ -16252,7 +16277,8 @@ } 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(); @@ -16274,7 +16300,8 @@ 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); Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -359,6 +359,10 @@ - The Fix-It emitted for unused labels used to expand to the next line, which caused visual oddities now that Clang shows more than one line of code snippet. This has been fixed and the Fix-It now only spans to the end of the ``:``. +- Clang constexpr evaluator now displays member function calls more precisely + by making use of the syntactical structure of function calls. This avoids display + of syntactically invalid codes in diagnostics. + (`#57081: <https://github.com/llvm/llvm-project/issues/57081>`_) Bug Fixes in This Version -------------------------
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits