[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
zwuis wrote: > Can you check this case with your build? Also pass this test. https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
hubert-reinterpretcast wrote: > PS: Sorry for misunderstanding the original issue. Totally understandable. Thanks for following up on this. > These changes pass all tests above: Can you check this case with your build? ```cpp struct A { int x; }; char q(int *); short q(int A::*); template constexpr int f(char (*)[sizeof(q(&T::x))]) { return 1; } template constexpr int f(char (*)[sizeof(q(&(T::x)))]) { return 2; } constexpr int g(char (*p)[sizeof(char)] = 0) { return f(p); } constexpr int h(char (*p)[sizeof(short)] = 0) { return f(p); } static_assert(g() == 2); static_assert(h() == 1); ``` https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
zwuis wrote: These changes pass all tests above: ```diff -if (isa(op) && cast(op)->getQualifier()) { +if (isa(op) && cast(op)->getQualifier() && +!isa(OrigOp.get())) { DeclContext *Ctx = dcl->getDeclContext(); if (Ctx && Ctx->isRecord()) { if (dcl->getType()->isReferenceType()) { Diag(OpLoc, diag::err_cannot_form_pointer_to_member_of_reference_type) << dcl->getDeclName() << dcl->getType(); 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(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(Ctx)->isAnonymousStructOrUnion()) Ctx = Ctx->getParent(); QualType MPTy = Context.getMemberPointerType( op->getType(), Context.getTypeDeclType(cast(Ctx)).getTypePtr()); // Under the MS ABI, lock down the inheritance model now. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) (void)isCompleteType(OpLoc, MPTy); return MPTy; } } ``` PS: Sorry for misunderstanding the original issue. https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
AaronBallman wrote: > I can try to look at that this week. Either way be ill-formed is much better > than being incorrect Thank you @cor3ntin! If it looks like you won't have a solution by Monday sometime, let's revert the changes so they don't end up on the release branch. We can cherry-pick if we think we have a rock solid solution, if needs be. https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
hubert-reinterpretcast wrote: For info, the cases where the _id-expression_ is transformed into a class member access expression (`q` and `h` below) do not run into this code (see https://cplusplus.github.io/CWG/issues/2902.html regarding said transformation): ```cpp #include struct S { int x; bool q = std::is_same_v; // OK static void f() { static_assert(std::is_same_v, ""); // OK } void g(this const S &) { static_assert(std::is_same_v, ""); // OK } void h() const { static_assert(std::is_same_v, ""); // OK } }; static_assert(S{0}.q); ``` https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
hubert-reinterpretcast wrote: I think (at least part of) the fix is to add a condition to https://github.com/llvm/llvm-project/blob/21e6777957457451196084cd48ebc42bce9619f0/clang/lib/Sema/SemaExpr.cpp#L14117-L14120 that the operand is not parenthesized. For reference, the address-of-member-function case checks for parentheses this way: https://github.com/llvm/llvm-project/blob/21e6777957457451196084cd48ebc42bce9619f0/clang/lib/Sema/SemaExpr.cpp#L13908-L13912 This should address the pre-existing bug with: ```cpp namespace std { template struct is_same { static constexpr bool value = false; }; template struct is_same { static constexpr bool value = true; }; } struct S { int &x; static_assert(std::is_same::value, ""); }; ``` https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
cor3ntin wrote: I can try to look at that this week. Either way be ill-formed is much better than being incorrect https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
AaronBallman wrote: Thank you for spotting this, btw! Given the proximity to the branch date, I lean towards (1) to give us time to figure out how to properly do (3) unless someone is starting on (3) Real Soon Now™. Any disagreement @cor3ntin ? https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
hubert-reinterpretcast wrote: The optics of having something in the release notes about this (if the bug is not fixed properly) is not good. Meaning that I am leaning towards options (1) or (3). https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
hubert-reinterpretcast wrote: > Or is there a deeper issue here and I'm not seeing it? The previous Clang behaviour produced the wrong type as the result. So the choices are to: 1. Do the old wrong thing: silent incorrect behaviour 2. Do the new wrong thing: produce diagnostic that may confuse users 3. Fix the type associated with the expression https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
AaronBallman wrote: If I'm following along correctly, both of those `static_assert`s should be accepted from your first example because `decltype` is an unevaluated context and the fix would be to change: ``` if (isa(OrigOp.get())) { ``` to instead be: ``` if (isa(OrigOp.get()) && !SemaRef.isUnevaluatedContext()) { ``` ? Or is there a deeper issue here and I'm not seeing it? https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
hubert-reinterpretcast wrote: Indeed, the new diagnostic is never valid because the permission to name non-static data members in unevaluated operands is not restricted by scope: https://eel.is/c++draft/expr.prim.id.general#4.3 https://gcc.godbolt.org/z/h4eTT984M: ```cpp namespace std { template struct is_same { static constexpr bool value = false; }; template struct is_same { static constexpr bool value = true; }; } struct S { int x; static_assert(std::is_same::value, ""); static_assert(std::is_same::value, ""); }; static_assert(std::is_same::value, ""); static_assert(std::is_same::value, ""); ``` https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
hubert-reinterpretcast wrote: @cor3ntin @AaronBallman, the new diagnostic triggers for valid code (https://gcc.godbolt.org/z/fMvEaGabG): ```cpp #include struct S { int x; static_assert(std::is_same::value, ""); static_assert(std::is_same::value, ""); }; ``` Either the first `static_assert` is invalid or both `static_assert`s are valid. https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
github-actions[bot] wrote: @zwuis Congratulations on having your first Pull Request (PR) merged into the LLVM Project! Your changes will be combined with recent changes from other authors, then tested by our [build bots](https://lab.llvm.org/buildbot/). If there is a problem with a build, you may receive a report in an email or a comment on this PR. Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues. How to do this, and the rest of the post-merge process, is covered in detail [here](https://llvm.org/docs/MyFirstTypoFix.html#myfirsttypofix-issues-after-landing-your-pr). If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of [LLVM development](https://llvm.org/docs/DeveloperPolicy.html#patch-reversion-policy). You can fix your changes and open a new PR to merge them again. If you don't get any reports, no action is required from you. Your changes are working as expected, well done! https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
https://github.com/cor3ntin closed https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
zwuis wrote: > @zwuis Thanks for your contribution. Will you need me to merge that for you? Yes. Thanks for your review! https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
cor3ntin wrote: @zwuis Thanks for your contribution. Will you need me to merge that for you? https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
https://github.com/zwuis updated https://github.com/llvm/llvm-project/pull/89713 >From f6fd1e5e5f42b3c72cb5aeaf9e6d4e91d5424bee Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Tue, 23 Apr 2024 14:56:12 +0800 Subject: [PATCH 1/6] Add missing check when making pointer to member --- clang/lib/Sema/SemaExpr.cpp| 11 +++ .../CXX/expr/expr.unary/expr.unary.op/p3.cpp | 18 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 5c861467bc1023..824667fb722365 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -14644,6 +14644,17 @@ 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(OrigOp.get())) { +// `op->getEndLoc()` is the last part of the qualified-id. +// For example, "baz" in "foo::bar::baz". +Diag(op->getEndLoc(), diag::err_invalid_non_static_member_use) +<< dcl->getDeclName() << op->getSourceRange(); +return QualType(); + } + while (cast(Ctx)->isAnonymousStructOrUnion()) Ctx = Ctx->getParent(); diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 08ab0ca56fb632..73d850a6839da7 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only %s -verify -// expected-no-diagnostics namespace rdar10544564 { // Check that we don't attempt to use an overloaded operator& when @@ -27,3 +26,20 @@ namespace rdar10544564 { X (Y::*func_mem_ptr1)() = &Y::memfunc1; X (Y::*func_mem_ptr2)() = &Y::memfunc2; } + +namespace test2 { + struct A { +int val; +void func() {} + }; + + void test() { +decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}} +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}} + } +} >From 22b18d32d79e5dcd0390aa17c454f373e565868a Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Wed, 24 Apr 2024 17:21:14 +0800 Subject: [PATCH 2/6] Apply suggestion from cor3ntin Co-authored-by: cor3ntin --- clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 73d850a6839da7..3e99b333d0e584 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -27,7 +27,7 @@ namespace rdar10544564 { X (Y::*func_mem_ptr2)() = &Y::memfunc2; } -namespace test2 { +namespace GH40906 { struct A { int val; void func() {} >From 81fd55780b34c92566bdfb7fc1a2cde690675d66 Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Wed, 24 Apr 2024 17:39:45 +0800 Subject: [PATCH 3/6] Move tests to the right place --- .../CXX/expr/expr.unary/expr.unary.op/p3.cpp | 18 +- .../CXX/expr/expr.unary/expr.unary.op/p4.cpp | 17 + 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 3e99b333d0e584..08ab0ca56fb632 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only %s -verify +// expected-no-diagnostics namespace rdar10544564 { // Check that we don't attempt to use an overloaded operator& when @@ -26,20 +27,3 @@ namespace rdar10544564 { X (Y::*func_mem_ptr1)() = &Y::memfunc1; X (Y::*func_mem_ptr2)() = &Y::memfunc2; } - -namespace GH40906 { - struct A { -int val; -void func() {} - }; - - void test() { -decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}} -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); // expec
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
https://github.com/zwuis updated https://github.com/llvm/llvm-project/pull/89713 >From f6fd1e5e5f42b3c72cb5aeaf9e6d4e91d5424bee Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Tue, 23 Apr 2024 14:56:12 +0800 Subject: [PATCH 1/6] Add missing check when making pointer to member --- clang/lib/Sema/SemaExpr.cpp| 11 +++ .../CXX/expr/expr.unary/expr.unary.op/p3.cpp | 18 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 5c861467bc1023..824667fb722365 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -14644,6 +14644,17 @@ 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(OrigOp.get())) { +// `op->getEndLoc()` is the last part of the qualified-id. +// For example, "baz" in "foo::bar::baz". +Diag(op->getEndLoc(), diag::err_invalid_non_static_member_use) +<< dcl->getDeclName() << op->getSourceRange(); +return QualType(); + } + while (cast(Ctx)->isAnonymousStructOrUnion()) Ctx = Ctx->getParent(); diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 08ab0ca56fb632..73d850a6839da7 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only %s -verify -// expected-no-diagnostics namespace rdar10544564 { // Check that we don't attempt to use an overloaded operator& when @@ -27,3 +26,20 @@ namespace rdar10544564 { X (Y::*func_mem_ptr1)() = &Y::memfunc1; X (Y::*func_mem_ptr2)() = &Y::memfunc2; } + +namespace test2 { + struct A { +int val; +void func() {} + }; + + void test() { +decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}} +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}} + } +} >From 22b18d32d79e5dcd0390aa17c454f373e565868a Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Wed, 24 Apr 2024 17:21:14 +0800 Subject: [PATCH 2/6] Apply suggestion from cor3ntin Co-authored-by: cor3ntin --- clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 73d850a6839da7..3e99b333d0e584 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -27,7 +27,7 @@ namespace rdar10544564 { X (Y::*func_mem_ptr2)() = &Y::memfunc2; } -namespace test2 { +namespace GH40906 { struct A { int val; void func() {} >From 81fd55780b34c92566bdfb7fc1a2cde690675d66 Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Wed, 24 Apr 2024 17:39:45 +0800 Subject: [PATCH 3/6] Move tests to the right place --- .../CXX/expr/expr.unary/expr.unary.op/p3.cpp | 18 +- .../CXX/expr/expr.unary/expr.unary.op/p4.cpp | 17 + 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 3e99b333d0e584..08ab0ca56fb632 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only %s -verify +// expected-no-diagnostics namespace rdar10544564 { // Check that we don't attempt to use an overloaded operator& when @@ -26,20 +27,3 @@ namespace rdar10544564 { X (Y::*func_mem_ptr1)() = &Y::memfunc1; X (Y::*func_mem_ptr2)() = &Y::memfunc2; } - -namespace GH40906 { - struct A { -int val; -void func() {} - }; - - void test() { -decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}} -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); // expec
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
@@ -27,3 +26,20 @@ namespace rdar10544564 { X (Y::*func_mem_ptr1)() = &Y::memfunc1; X (Y::*func_mem_ptr2)() = &Y::memfunc2; } + +namespace test2 { + struct A { +int val; +void func() {} + }; + + void test() { +decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}} +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}} zwuis wrote: > I think creating an issue, or a new PR is the way to go. Would that work for > you? Yes. Issue made: #90822. I will create PR in a few days. https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
https://github.com/cor3ntin approved this pull request. Sorry for the delayed reply. LGTM, thank you for your contribution! https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
@@ -27,3 +26,20 @@ namespace rdar10544564 { X (Y::*func_mem_ptr1)() = &Y::memfunc1; X (Y::*func_mem_ptr2)() = &Y::memfunc2; } + +namespace test2 { + struct A { +int val; +void func() {} + }; + + void test() { +decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}} +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}} cor3ntin wrote: I think creating an issue, or a new PR is the way to go. Would that work for you? https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
@@ -27,3 +26,20 @@ namespace rdar10544564 { X (Y::*func_mem_ptr1)() = &Y::memfunc1; X (Y::*func_mem_ptr2)() = &Y::memfunc2; } + +namespace test2 { + struct A { +int val; +void func() {} + }; + + void test() { +decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}} +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}} zwuis wrote: > This inconsistency is irrelevant to issue 40906. I am confused about the > following questions: > > 1. Do I need to remove these tests? > 2. Do I need to fix this inconsistency in this PR, or a new PR? > 3. Should I open an issue for it? @cor3ntin Could you give me some ideas for these questions? Thank you! https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
t3nsor wrote: > @t3nsor Do you know the reason for the "not enclosed in parameters" in > https://eel.is/c++draft/expr.unary.op#4 ? No I don't. If I had to guess, it might be because adding parentheses is intended to be used as a way to not create a pointer to member (and instead get an ordinary pointer to a member named by a qualified name) sort of like how parentheses can be used to suppress ADL. https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
https://github.com/zwuis edited https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
https://github.com/zwuis updated https://github.com/llvm/llvm-project/pull/89713 >From f6fd1e5e5f42b3c72cb5aeaf9e6d4e91d5424bee Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Tue, 23 Apr 2024 14:56:12 +0800 Subject: [PATCH 1/5] Add missing check when making pointer to member --- clang/lib/Sema/SemaExpr.cpp| 11 +++ .../CXX/expr/expr.unary/expr.unary.op/p3.cpp | 18 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 5c861467bc1023..824667fb722365 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -14644,6 +14644,17 @@ 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(OrigOp.get())) { +// `op->getEndLoc()` is the last part of the qualified-id. +// For example, "baz" in "foo::bar::baz". +Diag(op->getEndLoc(), diag::err_invalid_non_static_member_use) +<< dcl->getDeclName() << op->getSourceRange(); +return QualType(); + } + while (cast(Ctx)->isAnonymousStructOrUnion()) Ctx = Ctx->getParent(); diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 08ab0ca56fb632..73d850a6839da7 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only %s -verify -// expected-no-diagnostics namespace rdar10544564 { // Check that we don't attempt to use an overloaded operator& when @@ -27,3 +26,20 @@ namespace rdar10544564 { X (Y::*func_mem_ptr1)() = &Y::memfunc1; X (Y::*func_mem_ptr2)() = &Y::memfunc2; } + +namespace test2 { + struct A { +int val; +void func() {} + }; + + void test() { +decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}} +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}} + } +} >From 22b18d32d79e5dcd0390aa17c454f373e565868a Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Wed, 24 Apr 2024 17:21:14 +0800 Subject: [PATCH 2/5] Apply suggestion from cor3ntin Co-authored-by: cor3ntin --- clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 73d850a6839da7..3e99b333d0e584 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -27,7 +27,7 @@ namespace rdar10544564 { X (Y::*func_mem_ptr2)() = &Y::memfunc2; } -namespace test2 { +namespace GH40906 { struct A { int val; void func() {} >From 81fd55780b34c92566bdfb7fc1a2cde690675d66 Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Wed, 24 Apr 2024 17:39:45 +0800 Subject: [PATCH 3/5] Move tests to the right place --- .../CXX/expr/expr.unary/expr.unary.op/p3.cpp | 18 +- .../CXX/expr/expr.unary/expr.unary.op/p4.cpp | 17 + 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 3e99b333d0e584..08ab0ca56fb632 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only %s -verify +// expected-no-diagnostics namespace rdar10544564 { // Check that we don't attempt to use an overloaded operator& when @@ -26,20 +27,3 @@ namespace rdar10544564 { X (Y::*func_mem_ptr1)() = &Y::memfunc1; X (Y::*func_mem_ptr2)() = &Y::memfunc2; } - -namespace GH40906 { - struct A { -int val; -void func() {} - }; - - void test() { -decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}} -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); // expec
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
cor3ntin wrote: @t3nsor Do you know the reason for the "not enclosed in parameters" in https://eel.is/c++draft/expr.unary.op#4 ? https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
@@ -27,3 +26,20 @@ namespace rdar10544564 { X (Y::*func_mem_ptr1)() = &Y::memfunc1; X (Y::*func_mem_ptr2)() = &Y::memfunc2; } + +namespace test2 { + struct A { +int val; +void func() {} + }; + + void test() { +decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}} +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}} zwuis wrote: > I would expect `err_invalid_non_static_member_use` to be used there too (or > rather, that case should be consistent with above) This inconsistency is irrelevant to PR 40906. I am confused about the following questions: 1. Do I need to remove these tests? 2. Do I need to fix this inconsistency in this PR, or a new PR? 3. Should I open an issue for it? https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
https://github.com/zwuis updated https://github.com/llvm/llvm-project/pull/89713 >From f6fd1e5e5f42b3c72cb5aeaf9e6d4e91d5424bee Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Tue, 23 Apr 2024 14:56:12 +0800 Subject: [PATCH 1/3] Add missing check when making pointer to member --- clang/lib/Sema/SemaExpr.cpp| 11 +++ .../CXX/expr/expr.unary/expr.unary.op/p3.cpp | 18 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 5c861467bc1023..824667fb722365 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -14644,6 +14644,17 @@ 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(OrigOp.get())) { +// `op->getEndLoc()` is the last part of the qualified-id. +// For example, "baz" in "foo::bar::baz". +Diag(op->getEndLoc(), diag::err_invalid_non_static_member_use) +<< dcl->getDeclName() << op->getSourceRange(); +return QualType(); + } + while (cast(Ctx)->isAnonymousStructOrUnion()) Ctx = Ctx->getParent(); diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 08ab0ca56fb632..73d850a6839da7 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only %s -verify -// expected-no-diagnostics namespace rdar10544564 { // Check that we don't attempt to use an overloaded operator& when @@ -27,3 +26,20 @@ namespace rdar10544564 { X (Y::*func_mem_ptr1)() = &Y::memfunc1; X (Y::*func_mem_ptr2)() = &Y::memfunc2; } + +namespace test2 { + struct A { +int val; +void func() {} + }; + + void test() { +decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}} +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}} + } +} >From 22b18d32d79e5dcd0390aa17c454f373e565868a Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Wed, 24 Apr 2024 17:21:14 +0800 Subject: [PATCH 2/3] Apply suggestion from cor3ntin Co-authored-by: cor3ntin --- clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 73d850a6839da7..3e99b333d0e584 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -27,7 +27,7 @@ namespace rdar10544564 { X (Y::*func_mem_ptr2)() = &Y::memfunc2; } -namespace test2 { +namespace GH40906 { struct A { int val; void func() {} >From 81fd55780b34c92566bdfb7fc1a2cde690675d66 Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Wed, 24 Apr 2024 17:39:45 +0800 Subject: [PATCH 3/3] Move tests to the right place --- .../CXX/expr/expr.unary/expr.unary.op/p3.cpp | 18 +- .../CXX/expr/expr.unary/expr.unary.op/p4.cpp | 17 + 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 3e99b333d0e584..08ab0ca56fb632 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only %s -verify +// expected-no-diagnostics namespace rdar10544564 { // Check that we don't attempt to use an overloaded operator& when @@ -26,20 +27,3 @@ namespace rdar10544564 { X (Y::*func_mem_ptr1)() = &Y::memfunc1; X (Y::*func_mem_ptr2)() = &Y::memfunc2; } - -namespace GH40906 { - struct A { -int val; -void func() {} - }; - - void test() { -decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}} -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); // expec
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
https://github.com/zwuis updated https://github.com/llvm/llvm-project/pull/89713 >From f6fd1e5e5f42b3c72cb5aeaf9e6d4e91d5424bee Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Tue, 23 Apr 2024 14:56:12 +0800 Subject: [PATCH 1/3] Add missing check when making pointer to member --- clang/lib/Sema/SemaExpr.cpp| 11 +++ .../CXX/expr/expr.unary/expr.unary.op/p3.cpp | 18 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 5c861467bc1023..824667fb722365 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -14644,6 +14644,17 @@ 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(OrigOp.get())) { +// `op->getEndLoc()` is the last part of the qualified-id. +// For example, "baz" in "foo::bar::baz". +Diag(op->getEndLoc(), diag::err_invalid_non_static_member_use) +<< dcl->getDeclName() << op->getSourceRange(); +return QualType(); + } + while (cast(Ctx)->isAnonymousStructOrUnion()) Ctx = Ctx->getParent(); diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 08ab0ca56fb632..73d850a6839da7 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only %s -verify -// expected-no-diagnostics namespace rdar10544564 { // Check that we don't attempt to use an overloaded operator& when @@ -27,3 +26,20 @@ namespace rdar10544564 { X (Y::*func_mem_ptr1)() = &Y::memfunc1; X (Y::*func_mem_ptr2)() = &Y::memfunc2; } + +namespace test2 { + struct A { +int val; +void func() {} + }; + + void test() { +decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}} +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}} + } +} >From 22b18d32d79e5dcd0390aa17c454f373e565868a Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Wed, 24 Apr 2024 17:21:14 +0800 Subject: [PATCH 2/3] Apply suggestion from cor3ntin Co-authored-by: cor3ntin --- clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 73d850a6839da7..3e99b333d0e584 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -27,7 +27,7 @@ namespace rdar10544564 { X (Y::*func_mem_ptr2)() = &Y::memfunc2; } -namespace test2 { +namespace GH40906 { struct A { int val; void func() {} >From 4481d735c5a5eb266b9ce9aad93af818a8b8d49f Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Wed, 24 Apr 2024 17:39:45 +0800 Subject: [PATCH 3/3] Move tests to the right place --- .../CXX/expr/expr.unary/expr.unary.op/p3.cpp| 17 - .../CXX/expr/expr.unary/expr.unary.op/p4.cpp| 17 + 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 3e99b333d0e584..2dd6b23fa02496 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -26,20 +26,3 @@ namespace rdar10544564 { X (Y::*func_mem_ptr1)() = &Y::memfunc1; X (Y::*func_mem_ptr2)() = &Y::memfunc2; } - -namespace GH40906 { - struct A { -int val; -void func() {} - }; - - void test() { -decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}} -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}} - } -} diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp b/clang/test/CXX/expr/expr.unary/exp
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
https://github.com/zwuis updated https://github.com/llvm/llvm-project/pull/89713 >From f6fd1e5e5f42b3c72cb5aeaf9e6d4e91d5424bee Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Tue, 23 Apr 2024 14:56:12 +0800 Subject: [PATCH 1/2] Add missing check when making pointer to member --- clang/lib/Sema/SemaExpr.cpp| 11 +++ .../CXX/expr/expr.unary/expr.unary.op/p3.cpp | 18 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 5c861467bc1023..824667fb722365 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -14644,6 +14644,17 @@ 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(OrigOp.get())) { +// `op->getEndLoc()` is the last part of the qualified-id. +// For example, "baz" in "foo::bar::baz". +Diag(op->getEndLoc(), diag::err_invalid_non_static_member_use) +<< dcl->getDeclName() << op->getSourceRange(); +return QualType(); + } + while (cast(Ctx)->isAnonymousStructOrUnion()) Ctx = Ctx->getParent(); diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 08ab0ca56fb632..73d850a6839da7 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only %s -verify -// expected-no-diagnostics namespace rdar10544564 { // Check that we don't attempt to use an overloaded operator& when @@ -27,3 +26,20 @@ namespace rdar10544564 { X (Y::*func_mem_ptr1)() = &Y::memfunc1; X (Y::*func_mem_ptr2)() = &Y::memfunc2; } + +namespace test2 { + struct A { +int val; +void func() {} + }; + + void test() { +decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}} +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}} + } +} >From 22b18d32d79e5dcd0390aa17c454f373e565868a Mon Sep 17 00:00:00 2001 From: YanzuoLiu Date: Wed, 24 Apr 2024 17:21:14 +0800 Subject: [PATCH 2/2] Apply suggestion from cor3ntin Co-authored-by: cor3ntin --- clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp index 73d850a6839da7..3e99b333d0e584 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -27,7 +27,7 @@ namespace rdar10544564 { X (Y::*func_mem_ptr2)() = &Y::memfunc2; } -namespace test2 { +namespace GH40906 { struct A { int val; void func() {} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
@@ -14644,6 +14644,17 @@ 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(OrigOp.get())) { +// `op->getEndLoc()` is the last part of the qualified-id. +// For example, "baz" in "foo::bar::baz". +Diag(op->getEndLoc(), diag::err_invalid_non_static_member_use) +<< dcl->getDeclName() << op->getSourceRange(); AaronBallman wrote: We should also add a fix-it to remove the parentheses as a kindness to the user. https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
https://github.com/AaronBallman edited https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
https://github.com/AaronBallman commented: Thank you for the fix! You should also add a release note to clang/docs/ReleaseNotes.rst so that users know about the improvement. https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)
https://github.com/AaronBallman edited https://github.com/llvm/llvm-project/pull/89713 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits