diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -314,6 +314,9 @@ is an incomplete type. (`#55175: `_, and fixes an incorrect mention of ``alignof`` in a diagnostic about ``alignas``). +- Clang constexpr evaluator now displays member function calls by using dot operator + rather than arrow operator in notes to avoid display of syntactically invalid code. + (`#57081: `_). Bug Fixes in This Version ------------------------- diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -1919,10 +1919,11 @@ 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 << '('; + Val.printPretty( + Out, Info.Ctx, + Info.Ctx.getLValueReferenceType(This->Designator.MostDerivedType)); + Out << "." << *Callee << '('; + IsMemberCall = false; } diff --git a/clang/test/AST/Interp/constexpr-nqueens.cpp b/clang/test/AST/Interp/constexpr-nqueens.cpp --- a/clang/test/AST/Interp/constexpr-nqueens.cpp +++ b/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 'Board().addQueen(0, 0)}} \ // expected-note {{in call to '&Board()->addQueen(0, 0)}} N, Col, Row+1, B) : buildBoardScan(N, Col, Row + 1, B); diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp +++ b/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 diff --git a/clang/test/CXX/temp/temp.param/p8-cxx20.cpp b/clang/test/CXX/temp/temp.param/p8-cxx20.cpp --- a/clang/test/CXX/temp/temp.param/p8-cxx20.cpp +++ b/clang/test/CXX/temp/temp.param/p8-cxx20.cpp @@ -61,5 +61,5 @@ template struct Z {}; Z z1; - Z z2; // expected-error {{non-type template argument is not a constant expression}} expected-note-re {{in call to '{{.*}}->~D()'}} + Z z2; // expected-error {{non-type template argument is not a constant expression}} expected-note-re {{in call to '{{.*}}.~D()'}} } diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -975,7 +975,7 @@ int n; }; constexpr int S::f() const { - return static_cast(this)->n; // expected-note {{cannot cast}} + return static_cast(this)->n; // expected-note 5{{cannot cast}} } constexpr int S::g() const { // FIXME: Better diagnostic for this. @@ -984,8 +984,16 @@ // 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 'sobj.f()'}} +static_assert(slref.f(), ""); // expected-error {{constant expression}} expected-note {{in call to 'sobj.f()'}} +static_assert(srref.f(), ""); // expected-error {{constant expression}} expected-note {{in call to 'S().f()'}} static_assert(T(3).f() == 3, ""); static_assert(T(4).g() == 4, ""); diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -840,13 +840,13 @@ copy fail1{good0}; // expected-error {{call to consteval function 'defaulted_special_member_template::copy::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::operator=' is not a constant expression}} \ - expected-note {{in call to '&fail1->operator=(good0)'}} + expected-note {{in call to 'fail1.operator=(good0)'}} move good1; move fail2{static_cast&&>(good1)}; // expected-error {{call to consteval function 'defaulted_special_member_template::move::move' is not a constant expression}} \ expected-note {{in call to 'move(good1)'}} fail2 = static_cast&&>(good1); // expected-error {{call to consteval function 'defaulted_special_member_template::move::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 diff --git a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp --- a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp +++ b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp @@ -296,7 +296,7 @@ void f() { X().f(); Y().f(); - constexpr int q = Y().f(); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to '&Y()->f()'}} + constexpr int q = Y().f(); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'Y().f()'}} } struct NonLiteral { ~NonLiteral(); } nl; // cxx14-note {{user-provided destructor}} // cxx20_23-note@-1 {{'NonLiteral' is not literal because its destructor is not constexpr}}