[C++20] [Modules] Fix a crash when instantiate hidden friends
authorChuanqi Xu <yedeng.yd@linux.alibaba.com>
Tue, 3 Jan 2023 05:35:45 +0000 (13:35 +0800)
committerChuanqi Xu <yedeng.yd@linux.alibaba.com>
Tue, 3 Jan 2023 05:37:57 +0000 (13:37 +0800)
Closes https://github.com/llvm/llvm-project/issues/54457.

This removes a FIXME we found previously. But we didn't remove the FIXME
that time due to the lack of the corresponding test. And now we found
the corresponding test so we can remove it.

clang/docs/ReleaseNotes.rst
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/test/Modules/pr54457.cppm [new file with mode: 0644]

index a06f409..0fe0097 100644 (file)
@@ -329,6 +329,8 @@ Bug Fixes
 - Fix sanity check when value initializing an empty union so that it takes into
   account anonymous structs which is a GNU extension. This fixes
   `Issue 58800 <https://github.com/llvm/llvm-project/issues/58800>`_
+- Fix an issue that triggers a crash if we instantiate a hidden friend functions.
+  This fixes `Issue 54457 <https://github.com/llvm/llvm-project/issues/54457>`_
 
 Improvements to Clang's diagnostics
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index a05ecea..a645ffe 100644 (file)
@@ -6155,9 +6155,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
 
       // Move to the outer template scope.
       if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) {
-        // FIXME: We should use `getNonTransparentDeclContext()` here instead
-        // of `getDeclContext()` once we find the invalid test case.
-        if (FD->getFriendObjectKind() && FD->getDeclContext()->isFileContext()){
+        if (FD->getFriendObjectKind() &&
+            FD->getNonTransparentDeclContext()->isFileContext()) {
           DC = FD->getLexicalDeclContext();
           continue;
         }
diff --git a/clang/test/Modules/pr54457.cppm b/clang/test/Modules/pr54457.cppm
new file mode 100644 (file)
index 0000000..ed67ec1
--- /dev/null
@@ -0,0 +1,61 @@
+// https://github.com/llvm/llvm-project/issues/54457
+//
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 %t/A.cppm -verify -S -o -
+// RUN: %clang_cc1 -std=c++20 %t/B.cppm -verify -S -o -
+// RUN: %clang_cc1 -std=c++20 %t/C.cppm -emit-module-interface -o %t/C.pcm
+// RUN: %clang_cc1 -std=c++20 %t/UseC.cppm -fprebuilt-module-path=%t -verify -S -o -
+
+//--- A.cppm
+// expected-no-diagnostics
+export module A;
+
+export template<typename T>
+struct s {
+       friend s f(s) {
+               return s();
+       }
+};
+
+void g() {
+       f(s<int>());
+}
+
+//--- B.cppm
+// expected-no-diagnostics
+export module B;
+
+export template<typename T>
+struct s {
+       friend constexpr auto f(s) -> s {
+               return s();
+       }
+};
+
+void g() {
+       constexpr auto first = f(s<int>());
+}
+
+//--- C.cppm
+// expected-no-diagnostics
+export module C;
+
+export template<typename StandardCharT, int N>
+struct basic_symbol_text {
+  template<int N2>
+  constexpr friend basic_symbol_text operator+(
+    const basic_symbol_text&, const basic_symbol_text<char, N2>&) noexcept
+  {
+    return basic_symbol_text{};
+  }
+};
+
+constexpr auto xxx = basic_symbol_text<char, 1>{} + basic_symbol_text<char, 1>{};
+
+//--- UseC.cppm
+// expected-no-diagnostics
+import C;
+void foo() {}