[clang] 8480c93 - [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (#89713)
via cfe-commits
cfe-commits at lists.llvm.org
Fri May 3 01:20:46 PDT 2024
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 <corentinjabot at 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}}
+ }
+}
More information about the cfe-commits
mailing list