From: Chuanqi Xu Date: Thu, 21 Jul 2022 09:19:11 +0000 (+0800) Subject: [C++20] [Modules] Avoid inifinite loop when iterating default args X-Git-Tag: upstream/15.0.7~991 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ea623af7c90f0c02fed72010a018cb1e259cca8d;p=platform%2Fupstream%2Fllvm.git [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. --- diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index aa87a33..242e1f8 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 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 0000000..eb66b70 --- /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 +class pair {}; + +template +class allocator {}; + +template +class my_traits {}; + +template > > +class unordered_map +{ +public: + unordered_map() {} +}; + +template struct my_enable_if {}; +template struct my_enable_if { using type = T; }; +template using my_enable_if_t = typename my_enable_if::type; + +template>, + class = my_enable_if_t<_InputIterator::value>> +unordered_map(_InputIterator, _InputIterator, _Allocator = _Allocator()) + -> unordered_map, my_traits<_InputIterator>, _Allocator>; + +template , + class _Allocator = allocator<_CharT> > + class basic_string; +typedef basic_string, allocator > string; + +template +class basic_string +{ +public: + basic_string(); + + template > + basic_string(_InputIterator __first, _InputIterator __last, const _Allocator& __a); + + void resize(unsigned __n, _CharT __c); +}; + +extern template void basic_string::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 mime_map; // expected-error {{missing '#include'; 'unordered_map' must be declared before it is used}} + // expected-note@* {{declaration here is not visible}}