Author: YanzuoLiu Date: 2024-05-03T10:20:42+02:00 New Revision: 8480c93e36b33c237540e20c97cda8fb3d196f1f
URL: https://github.com/llvm/llvm-project/commit/8480c93e36b33c237540e20c97cda8fb3d196f1f DIFF: https://github.com/llvm/llvm-project/commit/8480c93e36b33c237540e20c97cda8fb3d196f1f.diff LOG: [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (#89713) clang don't check whether the operand of the & operator is enclosed in parantheses when pointer to member is formed in unevaluated context, for example: ```cpp struct foo { int val; }; int main() { decltype(&(foo::val)) ptr; } ``` `decltype(&(foo::val))` should be invalid, but clang accepts it. This PR fixes this issue. Fixes #40906. --------- Co-authored-by: cor3ntin <corentinja...@gmail.com> Added: Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Sema/SemaExpr.cpp clang/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 3a68a6d5efe5fa..280d272f2c1b22 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -53,6 +53,8 @@ C++ Specific Potentially Breaking Changes it's negative spelling can be used to obtain compatibility with previous versions of clang. +- Clang now rejects pointer to member from parenthesized expression in unevaluated context such as ``decltype(&(foo::bar))``. (#GH40906). + ABI Changes in This Version --------------------------- - Fixed Microsoft name mangling of implicitly defined variables used for thread diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index fbb107679d94ba..b5ba4bc889f2e3 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7511,6 +7511,9 @@ def err_nested_non_static_member_use : Error< def warn_cxx98_compat_non_static_member_use : Warning< "use of non-static data member %0 in an unevaluated context is " "incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def err_form_ptr_to_member_from_parenthesized_expr : Error< + "cannot form pointer to member from a parenthesized expression; " + "did you mean to remove the parentheses?">; def err_invalid_incomplete_type_use : Error< "invalid use of incomplete type %0">; def err_builtin_func_cast_more_than_one_arg : Error< diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 0cca02c338954a..7190e50b156f7b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -14651,6 +14651,22 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { return QualType(); } + // C++11 [expr.unary.op] p4: + // A pointer to member is only formed when an explicit & is used and + // its operand is a qualified-id not enclosed in parentheses. + if (isa<ParenExpr>(OrigOp.get())) { + SourceLocation LeftParenLoc = OrigOp.get()->getBeginLoc(), + RightParenLoc = OrigOp.get()->getEndLoc(); + + Diag(LeftParenLoc, + diag::err_form_ptr_to_member_from_parenthesized_expr) + << SourceRange(OpLoc, RightParenLoc) + << FixItHint::CreateRemoval(LeftParenLoc) + << FixItHint::CreateRemoval(RightParenLoc); + + // Continuing might lead to better error recovery. + } + while (cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion()) Ctx = Ctx->getParent(); diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp index 537d676738bef8..162d59439d08ee 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp @@ -41,3 +41,20 @@ namespace test2 { int (A::*ptr)(int) = &(A::foo); // expected-error {{cannot create a non-constant pointer to member function}} } } + +namespace GH40906 { + struct A { + int val; + void func() {} + }; + + void test() { + decltype(&(A::val)) ptr1; // expected-error {{cannot form pointer to member from a parenthesized expression; did you mean to remove the parentheses?}} + int A::* ptr2 = &(A::val); // expected-error {{invalid use of non-static data member 'val'}} + + // FIXME: Error messages in these cases are less than clear, we can do + // better. + int size = sizeof(&(A::func)); // expected-error {{call to non-static member function without an object argument}} + void (A::* ptr3)() = &(A::func); // expected-error {{call to non-static member function without an object argument}} + } +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits