llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: None (Sirraide)

<details>
<summary>Changes</summary>

When analysing whether we should handle a binary expression as an overloaded 
operator call or a builtin operator, we were calling 
`checkPlaceholderForOverload()`, which takes care of any placeholders that are 
not overload sets—which would usually make sense since those need to be handled 
as part of overload resolution.

Unfortunately, we were also doing that for `.*`, which is not overloadable, and 
then proceeding to create a builtin operator anyway, which would crash if the 
RHS happened to be an unresolved overload set (due hitting an assertion in 
`CreateBuiltinBinOp()`—specifically, in one of its callees—in the `.*` case 
that makes sure its arguments aren’t placeholders).

This pr instead makes it so we check for *all* placeholders early if the 
operator is `.*`.

It’s worth noting that,
1. In the `.*` case, we now additionally also check for *any* placeholders (not 
just non-overload-sets) in the LHS; this shouldn’t make a difference, 
however—at least I couldn’t think of a way to trigger the assertion with an 
overload set as the LHS of `.*`; it is worth noting that the assertion in 
question would also complain if the LHS happened to be of placeholder type, 
though.
2. There is another case in which we also don’t perform overload 
resolution—namely `=` if the LHS is not of class or enumeration type after 
handling non-overload-set placeholders—as in the `.*` case, but similarly to 
1., I first couldn’t think of a way of getting this case to crash, and 
secondly, `CreateBuiltinBinOp()` doesn’t seem to care about placeholders in the 
LHS or RHS in the `=` case (from what I can tell, it, or rather one of its 
callees, only checks that the LHS is not a pseudo-object type, but those will 
have already been handled by the call to `checkPlaceholderForOverload()` by the 
time we get to this function), so I don’t think this case suffers from the same 
problem.

This fixes #<!-- -->53815.

---
Full diff: https://github.com/llvm/llvm-project/pull/83103.diff


2 Files Affected:

- (modified) clang/lib/Sema/SemaOverload.cpp (+17-5) 
- (added) clang/test/SemaCXX/gh53815.cpp (+21) 


``````````diff
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index c46f6338a5a125..f4b67e7b469418 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -14474,6 +14474,23 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation 
OpLoc,
                                        CurFPFeatureOverrides());
   }
 
+  // If this is the .* operator, which is not overloadable, just
+  // create a built-in binary operator.
+  if (Opc == BO_PtrMemD) {
+    auto CheckPlaceholder = [&](Expr *&Arg) {
+      ExprResult Res = CheckPlaceholderExpr(Arg);
+      if (!Res.isInvalid())
+        Arg = Res.get();
+      return Res.isInvalid();
+    };
+
+    // CreateBuiltinBinOp() doesn't like it if we tell it to create a '.*'
+    // expression that contains placeholders (in either the LHS or RHS).
+    if (CheckPlaceholder(Args[0]) || CheckPlaceholder(Args[1]))
+      return ExprError();
+    return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
+  }
+
   // Always do placeholder-like conversions on the RHS.
   if (checkPlaceholderForOverload(*this, Args[1]))
     return ExprError();
@@ -14493,11 +14510,6 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation 
OpLoc,
   if (Opc == BO_Assign && !Args[0]->getType()->isOverloadableType())
     return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
 
-  // If this is the .* operator, which is not overloadable, just
-  // create a built-in binary operator.
-  if (Opc == BO_PtrMemD)
-    return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
-
   // Build the overload set.
   OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator,
                                     OverloadCandidateSet::OperatorRewriteInfo(
diff --git a/clang/test/SemaCXX/gh53815.cpp b/clang/test/SemaCXX/gh53815.cpp
new file mode 100644
index 00000000000000..326c911c7bfaf5
--- /dev/null
+++ b/clang/test/SemaCXX/gh53815.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
+// expected-no-diagnostics
+
+// Check that we don't crash due to forgetting to check for placeholders
+// in the RHS of '.*'.
+
+template <typename Fn>
+static bool has_explicitly_named_overload() {
+  return requires { Fn().*&Fn::operator(); };
+}
+
+int main() {
+  has_explicitly_named_overload<decltype([](auto){})>();
+}
+
+template <typename Fn>
+constexpr bool has_explicitly_named_overload_2() {
+  return requires { Fn().*&Fn::operator(); };
+}
+
+static_assert(!has_explicitly_named_overload_2<decltype([](auto){})>());

``````````

</details>


https://github.com/llvm/llvm-project/pull/83103
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to