Skip to content

Commit 8480c93

Browse files
zwuiscor3ntin
andauthored
[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 <[email protected]>
1 parent e4b04b3 commit 8480c93

File tree

4 files changed

+38
-0
lines changed

4 files changed

+38
-0
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ C++ Specific Potentially Breaking Changes
5353
it's negative spelling can be used to obtain compatibility with previous
5454
versions of clang.
5555

56+
- Clang now rejects pointer to member from parenthesized expression in unevaluated context such as ``decltype(&(foo::bar))``. (#GH40906).
57+
5658
ABI Changes in This Version
5759
---------------------------
5860
- Fixed Microsoft name mangling of implicitly defined variables used for thread

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7511,6 +7511,9 @@ def err_nested_non_static_member_use : Error<
75117511
def warn_cxx98_compat_non_static_member_use : Warning<
75127512
"use of non-static data member %0 in an unevaluated context is "
75137513
"incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
7514+
def err_form_ptr_to_member_from_parenthesized_expr : Error<
7515+
"cannot form pointer to member from a parenthesized expression; "
7516+
"did you mean to remove the parentheses?">;
75147517
def err_invalid_incomplete_type_use : Error<
75157518
"invalid use of incomplete type %0">;
75167519
def err_builtin_func_cast_more_than_one_arg : Error<

clang/lib/Sema/SemaExpr.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14651,6 +14651,22 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
1465114651
return QualType();
1465214652
}
1465314653

14654+
// C++11 [expr.unary.op] p4:
14655+
// A pointer to member is only formed when an explicit & is used and
14656+
// its operand is a qualified-id not enclosed in parentheses.
14657+
if (isa<ParenExpr>(OrigOp.get())) {
14658+
SourceLocation LeftParenLoc = OrigOp.get()->getBeginLoc(),
14659+
RightParenLoc = OrigOp.get()->getEndLoc();
14660+
14661+
Diag(LeftParenLoc,
14662+
diag::err_form_ptr_to_member_from_parenthesized_expr)
14663+
<< SourceRange(OpLoc, RightParenLoc)
14664+
<< FixItHint::CreateRemoval(LeftParenLoc)
14665+
<< FixItHint::CreateRemoval(RightParenLoc);
14666+
14667+
// Continuing might lead to better error recovery.
14668+
}
14669+
1465414670
while (cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion())
1465514671
Ctx = Ctx->getParent();
1465614672

clang/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,20 @@ namespace test2 {
4141
int (A::*ptr)(int) = &(A::foo); // expected-error {{cannot create a non-constant pointer to member function}}
4242
}
4343
}
44+
45+
namespace GH40906 {
46+
struct A {
47+
int val;
48+
void func() {}
49+
};
50+
51+
void test() {
52+
decltype(&(A::val)) ptr1; // expected-error {{cannot form pointer to member from a parenthesized expression; did you mean to remove the parentheses?}}
53+
int A::* ptr2 = &(A::val); // expected-error {{invalid use of non-static data member 'val'}}
54+
55+
// FIXME: Error messages in these cases are less than clear, we can do
56+
// better.
57+
int size = sizeof(&(A::func)); // expected-error {{call to non-static member function without an object argument}}
58+
void (A::* ptr3)() = &(A::func); // expected-error {{call to non-static member function without an object argument}}
59+
}
60+
}

0 commit comments

Comments
 (0)