[clang] 7ac308f - PR52073: Fix equivalence computation for lambda-expressions.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 8 13:54:12 PDT 2021


Author: Richard Smith
Date: 2021-10-08T13:54:01-07:00
New Revision: 7ac308fb8f283249b89851702aa07f3ed9ac86d4

URL: https://github.com/llvm/llvm-project/commit/7ac308fb8f283249b89851702aa07f3ed9ac86d4
DIFF: https://github.com/llvm/llvm-project/commit/7ac308fb8f283249b89851702aa07f3ed9ac86d4.diff

LOG: PR52073: Fix equivalence computation for lambda-expressions.

Distinct lambda expressions are always considered non-equivalent, so two
token-for-token identical function declarations whose signatures involve
lambda-expressions declare distinct functions.

Added: 
    

Modified: 
    clang/lib/AST/ItaniumMangle.cpp
    clang/lib/AST/StmtProfile.cpp
    clang/test/SemaCXX/lambda-unevaluated.cpp
    clang/www/cxx_status.html

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 34ad2b0b1d043..2d373c15031de 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -4181,7 +4181,6 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
   case Expr::ArrayInitIndexExprClass:
   case Expr::NoInitExprClass:
   case Expr::ParenListExprClass:
-  case Expr::LambdaExprClass:
   case Expr::MSPropertyRefExprClass:
   case Expr::MSPropertySubscriptExprClass:
   case Expr::TypoExprClass: // This should no longer exist in the AST by now.
@@ -4966,6 +4965,15 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
     break;
   }
 
+  case Expr::LambdaExprClass: {
+    // A lambda-expression can't appear in the signature of an
+    // externally-visible declaration, so there's no standard mangling for
+    // this, but mangling as a literal of the closure type seems reasonable.
+    Out << "L";
+    mangleType(Context.getASTContext().getRecordType(cast<LambdaExpr>(E)->getLambdaClass()));
+    Out << "E";
+  }
+
   case Expr::PackExpansionExprClass:
     NotPrimaryExpr();
     Out << "sp";

diff  --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 9c48491dca712..2184eb7aa0109 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -1933,30 +1933,9 @@ StmtProfiler::VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
 void
 StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) {
   VisitExpr(S);
-  for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
-                                 CEnd = S->explicit_capture_end();
-       C != CEnd; ++C) {
-    if (C->capturesVLAType())
-      continue;
-
-    ID.AddInteger(C->getCaptureKind());
-    switch (C->getCaptureKind()) {
-    case LCK_StarThis:
-    case LCK_This:
-      break;
-    case LCK_ByRef:
-    case LCK_ByCopy:
-      VisitDecl(C->getCapturedVar());
-      ID.AddBoolean(C->isPackExpansion());
-      break;
-    case LCK_VLAType:
-      llvm_unreachable("VLA type in explicit captures.");
-    }
-  }
-  // Note: If we actually needed to be able to match lambda
-  // expressions, we would have to consider parameters and return type
-  // here, among other things.
-  VisitStmt(S->getBody());
+  // C++20 [temp.over.link]p5:
+  //   Two lambda-expressions are never considered equivalent.
+  VisitDecl(S->getLambdaClass());
 }
 
 void

diff  --git a/clang/test/SemaCXX/lambda-unevaluated.cpp b/clang/test/SemaCXX/lambda-unevaluated.cpp
index 07fa0d94bc8e4..1a06528a1c063 100644
--- a/clang/test/SemaCXX/lambda-unevaluated.cpp
+++ b/clang/test/SemaCXX/lambda-unevaluated.cpp
@@ -29,3 +29,17 @@ template <class T>
 auto g(T) -> decltype([]() { T::invalid; } ());
 auto e = g(0); // expected-error{{no matching function for call}}
 // expected-note at -2 {{substitution failure}}
+
+namespace PR52073 {
+// OK, these are distinct functions not redefinitions.
+template<typename> void f(decltype([]{})) {} // expected-note {{candidate}}
+template<typename> void f(decltype([]{})) {} // expected-note {{candidate}}
+void use_f() { f<int>({}); } // expected-error {{ambiguous}}
+
+// Same.
+template<int N> void g(const char (*)[([]{ return N; })()]) {} // expected-note {{candidate}}
+template<int N> void g(const char (*)[([]{ return N; })()]) {} // expected-note {{candidate}}
+// FIXME: We instantiate the lambdas into the context of the function template,
+// so we think they're dependent and can't evaluate a call to them.
+void use_g() { g<6>(&"hello"); } // expected-error {{no matching function}}
+}

diff  --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index f6531ed01e49e..2be1fb4b68738 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -1021,11 +1021,7 @@ <h2 id="cxx20">C++20 implementation status</h2>
     <tr>
       <td>Lambdas in unevaluated contexts</td>
       <td><a href="https://wg21.link/p0315r4">P0315R4</a></td>
-      <td class="partial" align="center">
-        <details><summary>Clang 13</summary>
-          [temp.deduct] p9 is not yet implemented.
-        </details>
-      </td>
+      <td class="partial" align="center">Partial</td>
     </tr>
     <!-- Jacksonville papers -->
     <tr>


        


More information about the cfe-commits mailing list