[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