https://github.com/ChuanqiXu9 created 
https://github.com/llvm/llvm-project/pull/177899

Close https://github.com/llvm/llvm-project/issues/177385

The root cause of the problem is, when we decide to mangle a lamdba in a module 
interface while the ManglingContextDecl is nullptr, we didn't update 
ManglingContextDecl. So that the following use of ManglingContextDecl is an 
invalid value.

>From c42dc38cc6fc28dad30285b57b6b2cc0bdc6ab7b Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <[email protected]>
Date: Mon, 26 Jan 2026 13:36:35 +0800
Subject: [PATCH] [C++20] [Modules] Set ManglingContextDecl when we need to
 mangle a lambda but it's nullptr

Close https://github.com/llvm/llvm-project/issues/177385

The root cause of the problem is, when we decide to mangle a lamdba
in a module interface while the ManglingContextDecl is nullptr,
we didn't update ManglingContextDecl. So that the following use of
ManglingContextDecl is an invalid value.
---
 clang/lib/Sema/SemaLambda.cpp    |  23 ++---
 clang/test/Modules/pr177385.cppm | 165 +++++++++++++++++++++++++++++++
 2 files changed, 177 insertions(+), 11 deletions(-)
 create mode 100644 clang/test/Modules/pr177385.cppm

diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index e1b1cd3e04946..e74fe02bd0cf5 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -298,18 +298,19 @@ Sema::getCurrentMangleNumberContext(const DeclContext 
*DC) {
   // definition, as well as the initializers of data members, receive special
   // treatment. Identify them.
   Kind = [&]() {
+    // See discussion in https://github.com/itanium-cxx-abi/cxx-abi/issues/186
+    //
+    // zygoloid:
+    //    Yeah, I think the only cases left where lambdas don't need a
+    //    mangling are when they have (effectively) internal linkage or appear
+    //    in a non-inline function in a non-module translation unit.
     if (auto *ND = dyn_cast<NamedDecl>(ManglingContextDecl ? 
ManglingContextDecl
-                                                           : cast<Decl>(DC))) {
-      // See discussion in 
https://github.com/itanium-cxx-abi/cxx-abi/issues/186
-      //
-      // zygoloid:
-      //    Yeah, I think the only cases left where lambdas don't need a
-      //    mangling are when they have (effectively) internal linkage or 
appear
-      //    in a non-inline function in a non-module translation unit.
-      Module *M = ND->getOwningModule();
-      if (M && M->getTopLevelModule()->isNamedModuleUnit() &&
-          ND->isExternallyVisible())
-        return NonInlineInModulePurview;
+                                                           : cast<Decl>(DC));
+        ND && (ND->isInNamedModule() || ND->isFromGlobalModule()) &&
+        ND->isExternallyVisible()) {
+      if (!ManglingContextDecl)
+        ManglingContextDecl = const_cast<Decl *>(cast<Decl>(DC));
+      return NonInlineInModulePurview;
     }
 
     if (!ManglingContextDecl)
diff --git a/clang/test/Modules/pr177385.cppm b/clang/test/Modules/pr177385.cppm
new file mode 100644
index 0000000000000..02852ce3b6fe4
--- /dev/null
+++ b/clang/test/Modules/pr177385.cppm
@@ -0,0 +1,165 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: split-file %s %t
+// RUN: mkdir %t/tmp
+
+// RUN: %clang_cc1 -std=c++26 %t/std.cppm  -emit-module-interface -o %t/std.pcm
+// RUN: %clang_cc1 -std=c++26 %t/optional.cppm  -emit-module-interface -o 
%t/optional.pcm \
+// RUN:       -fmodule-file=std=%t/std.pcm
+// RUN: %clang_cc1 -std=c++26 %t/date.format.cppm  -emit-module-interface -o 
%t/date.format.pcm \
+// RUN:       -fmodule-file=std=%t/std.pcm \
+// RUN:       -fmodule-file=bopt.optional=%t/optional.pcm
+// RUN: %clang_cc1 -std=c++26 %t/annotated.cppm  -emit-module-interface -o 
%t/annotated.pcm \
+// RUN:       -fmodule-file=std=%t/std.pcm \
+// RUN:       -fmodule-file=bopt.optional=%t/optional.pcm \
+// RUN:       -fmodule-file=ldgr:date.format=%t/date.format.pcm
+// RUN: %clang_cc1 -std=c++26 %t/annotated.format.cppm  -emit-module-interface 
-o %t/annotated.format.pcm \
+// RUN:       -fmodule-file=std=%t/std.pcm \
+// RUN:       -fmodule-file=bopt.optional=%t/optional.pcm \
+// RUN:       -fmodule-file=ldgr:date.format=%t/date.format.pcm \
+// RUN:       -fmodule-file=ldgr:annotated=%t/annotated.pcm
+// RUN: %clang_cc1 -std=c++26 %t/date.test.cppm  -emit-module-interface -o 
%t/date.test.pcm \
+// RUN:       -fmodule-file=std=%t/std.pcm \
+// RUN:       -fmodule-file=bopt.optional=%t/optional.pcm \
+// RUN:       -fmodule-file=ldgr:date.format=%t/date.format.pcm \
+// RUN:       -fmodule-file=ldgr:annotated=%t/annotated.pcm \
+// RUN:       -fmodule-file=ldgr:annotated.format=%t/annotated.format.pcm
+// RUN: %clang_cc1 -std=c++26 -w %t/annotated.test.cpp -fsyntax-only -verify \
+// RUN:       -fmodule-file=std=%t/std.pcm \
+// RUN:       -fmodule-file=bopt.optional=%t/optional.pcm \
+// RUN:       -fmodule-file=ldgr:date.format=%t/date.format.pcm \
+// RUN:       -fmodule-file=ldgr:annotated=%t/annotated.pcm \
+// RUN:       -fmodule-file=ldgr:annotated.format=%t/annotated.format.pcm \
+// RUN:       -fmodule-file=ldgr:date.testlib=%t/date.test.pcm
+
+//--- std.cppm
+module;
+namespace std {
+inline namespace __1 {
+template <class _Tp> _Tp forward(_Tp);
+template <class... _Args>
+void __invoke(_Args... __args) noexcept(
+    noexcept(__builtin_invoke(forward(__args)...)));
+using string = char;
+struct in_place_t {
+} in_place;
+template <typename...> struct __traits;
+struct Trans_NS___visitation___base {
+  template <class _Visitor, class... _Vs>
+  static void __visit_alt(_Visitor, _Vs... __vs) {
+    __make_fmatrix<_Visitor, decltype(__vs)...>;
+  }
+  struct __dispatcher {
+    template <class _Fp, class... _Vs> static void __dispatch(_Vs... __vs) {
+      _Fp __f;
+      __invoke(__f, __vs...);
+    }
+  };
+  template <class _Fp, class... _Vs> static void __make_dispatch() {
+    __dispatcher::__dispatch<_Fp, _Vs...>;
+  }
+  template <class _Fp, class... _Vs> static void __make_fmatrix_impl() {
+    __make_dispatch<_Fp, _Vs...>;
+  }
+  template <class _Fp, class... _Vs> static void __make_fmatrix() {
+    __make_fmatrix_impl<_Fp, _Vs...>;
+  }
+};
+template <class> class __dtor;
+template <class... _Types> struct __dtor<__traits<_Types...>> {
+  ~__dtor() {
+    Trans_NS___visitation___base::__visit_alt([](auto) {}, this);
+  }
+};
+struct __move_constructor : __dtor<__traits<>> {};
+struct __assignment : __move_constructor {};
+struct __impl : __assignment {};
+template <class> struct variant {
+  __impl __impl_;
+};
+}
+}
+export module std;
+export namespace std {
+using std::forward;
+using std::in_place;
+using std::in_place_t;
+using std::string;
+using std::variant;
+}
+
+//--- optional.cppm
+export module bopt.optional;
+import std;
+namespace bopt {
+template <class T> struct wrapper {
+  template <class Func> wrapper(int, Func f) : value(std::forward(f)()) {}
+  T value;
+};
+template <class T> struct optional_base {
+  struct union_t {
+    T value_;
+  };
+  struct repr {
+    template <class OtherValue>
+    repr(OtherValue) : un_{0, [] { return union_t{}; }} {}
+    wrapper<union_t> un_;
+  };
+  template <class... Args>
+  optional_base(std::in_place_t, Args... args) : repr_{args...} {}
+  repr repr_;
+};
+export template <class T> struct optional : optional_base<T> {
+  optional();
+  template <class U> optional(U) : optional_base<T>{std::in_place, 0} {}
+  template <class U> constexpr void operator=(U) {
+    [] {};
+  }
+};
+}
+
+//--- date.format.cppm
+module ldgr:date.format;
+import bopt.optional;
+namespace ldgr {
+struct date_format {
+  template <class S> static int parse(S s) { bopt::optional<int> year{s}; }
+};
+}
+
+//--- annotated.cppm
+module ldgr:annotated;
+import std;
+import bopt.optional;
+struct lot_annotation {
+  using valuation_expr_t = std::variant<std::string>;
+  bopt::optional<valuation_expr_t> valuation_expr_;
+};
+struct annotated_amount {
+  lot_annotation lot_annotation_;
+};
+
+//--- annotated.format.cppm
+module ldgr:annotated.format;
+import :date.format;
+import :annotated;
+namespace ldgr {
+struct annotated_format {
+  static annotated_amount parse_default() {
+    bopt::optional<int> date;
+    date = date_format::parse(0);
+  }
+};
+}
+
+//--- date.test.cppm
+module ldgr:date.testlib;
+import :date.format;
+void date_from_string() { ldgr::date_format::parse(0); }
+
+//--- annotated.test.cpp
+// expected-no-diagnostics
+module ldgr:annotatedtest;
+import :annotated.format;
+import :date.testlib;
+int main() { ldgr::annotated_format::parse_default(); }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to