[clang] ea623af - [C++20] [Modules] Avoid inifinite loop when iterating default args

Chuanqi Xu via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 21 02:25:39 PDT 2022


Author: Chuanqi Xu
Date: 2022-07-21T17:25:05+08:00
New Revision: ea623af7c90f0c02fed72010a018cb1e259cca8d

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

LOG: [C++20] [Modules] Avoid inifinite loop when iterating default args

Currently, clang may meet an infinite loop in a very tricky case when it
iterates the default args. This patch tries to fix this by adding a
`fixed` check.

Added: 
    clang/test/Modules/inherited_arg.cppm

Modified: 
    clang/lib/Sema/SemaLookup.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index aa87a33ce8ae1..242e1f81d75c0 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -1615,7 +1615,10 @@ hasAcceptableDefaultArgument(Sema &S, const ParmDecl *D,
   if (!D->hasDefaultArgument())
     return false;
 
-  while (D) {
+  llvm::SmallDenseSet<const ParmDecl *, 4> Visited;
+  while (D && !Visited.count(D)) {
+    Visited.insert(D);
+
     auto &DefaultArg = D->getDefaultArgStorage();
     if (!DefaultArg.isInherited() && S.isAcceptable(D, Kind))
       return true;
@@ -1625,7 +1628,8 @@ hasAcceptableDefaultArgument(Sema &S, const ParmDecl *D,
       Modules->push_back(S.getOwningModule(NonConstD));
     }
 
-    // If there was a previous default argument, maybe its parameter is visible.
+    // If there was a previous default argument, maybe its parameter is
+    // acceptable.
     D = DefaultArg.getInheritedFrom();
   }
   return false;

diff  --git a/clang/test/Modules/inherited_arg.cppm b/clang/test/Modules/inherited_arg.cppm
new file mode 100644
index 0000000000000..eb66b70cdce33
--- /dev/null
+++ b/clang/test/Modules/inherited_arg.cppm
@@ -0,0 +1,78 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: cd %t
+//
+// RUN: %clang_cc1 -std=c++20 %t/A-B.cppm -I%t -emit-module-interface -o %t/A-B.pcm
+// RUN: %clang_cc1 -std=c++20 %t/A-C.cppm -I%t -emit-module-interface -o %t/A-C.pcm
+// RUN: %clang_cc1 -std=c++20 %t/A.cppm -emit-module-interface -fprebuilt-module-path=%t -o %t/A.pcm
+// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/Use.cpp -verify -fsyntax-only
+
+//--- foo.h
+template <typename U, typename T>
+class pair {};
+
+template <typename U>
+class allocator {};
+
+template <typename T>
+class my_traits {};
+
+template <class _Key, class _Tp,
+          class _Alloc = allocator<pair<const _Key, _Tp> > >
+class unordered_map
+{
+public:
+    unordered_map() {}
+};
+
+template<bool, class = void> struct my_enable_if {};
+template<class T> struct my_enable_if<true, T> { using type = T; };
+template<bool B, class T = void> using my_enable_if_t = typename my_enable_if<B, T>::type;
+
+template<class _InputIterator,
+         class _Allocator = allocator<my_traits<_InputIterator>>,
+         class = my_enable_if_t<_InputIterator::value>>
+unordered_map(_InputIterator, _InputIterator, _Allocator = _Allocator())
+  -> unordered_map<my_traits<_InputIterator>, my_traits<_InputIterator>, _Allocator>;
+
+template <class _CharT,
+          class _Traits = my_traits<_CharT>,
+          class _Allocator = allocator<_CharT> >
+    class basic_string;
+typedef basic_string<char, my_traits<char>, allocator<char> > string;
+
+template<class _CharT, class _Traits, class _Allocator>
+class basic_string
+{
+public:
+    basic_string();
+
+    template<class _InputIterator, class = my_enable_if_t<_InputIterator::value> > 
+            basic_string(_InputIterator __first, _InputIterator __last, const _Allocator& __a);
+
+    void resize(unsigned __n, _CharT __c);
+};
+
+extern template void basic_string<char>::resize(unsigned, char);
+
+//--- A-B.cppm
+module;
+#include "foo.h"
+export module A:B;
+export using ::string;
+
+//--- A-C.cppm
+module;
+#include "foo.h"
+export module A:C;
+
+//--- A.cppm
+export module A;
+export import :B;
+export import :C;
+
+//--- Use.cpp
+import A;
+string s;
+::unordered_map<int, int> mime_map; // expected-error {{missing '#include'; 'unordered_map' must be declared before it is used}}
+                                    // expected-note@* {{declaration here is not visible}}


        


More information about the cfe-commits mailing list