diff options
Diffstat (limited to 'clang/unittests/AST')
| -rw-r--r-- | clang/unittests/AST/ASTImporterTest.cpp | 117 | ||||
| -rw-r--r-- | clang/unittests/AST/TypePrinterTest.cpp | 65 |
2 files changed, 182 insertions, 0 deletions
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 4c7ea5e..1647906 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -3204,6 +3204,57 @@ TEST_P(ImportExpr, UnresolvedMemberExpr) { compoundStmt(has(callExpr(has(unresolvedMemberExpr()))))))))); } +TEST_P(ImportDecl, CycleInAutoTemplateSpec) { + MatchVerifier<Decl> Verifier; + const char *Code = R"( + template <class _CharT> + struct basic_string { + using value_type = _CharT; + }; + + template<typename T> + struct basic_string_view { + using value_type = T; + }; + + using string_view = basic_string_view<char>; + using string = basic_string<char>; + + template<typename T> + struct span { + }; + + template <typename StringT> + auto StrCatT(span<const StringT> pieces) { + basic_string<typename StringT::value_type> result; + return result; + } + + string StrCat(span<const string_view> pieces) { + return StrCatT(pieces); + } + + string StrCat(span<const string> pieces) { + return StrCatT(pieces); + } + + template <typename T> + auto declToImport(T pieces) { + return StrCat(pieces); + } + + void test() { + span<const string> pieces; + auto result = declToImport(pieces); + } +)"; + // This test reproduces the StrCatT recursion pattern with concepts and span + // that may cause infinite recursion during AST import due to circular + // dependencies + testImport(Code, Lang_CXX20, "", Lang_CXX20, Verifier, + functionTemplateDecl(hasName("declToImport"))); +} + TEST_P(ImportExpr, ConceptNoRequirement) { MatchVerifier<Decl> Verifier; const char *Code = R"( @@ -3300,6 +3351,72 @@ TEST_P(ImportExpr, ConceptNestedNonInstantiationDependentRequirement) { conceptDecl(has(requiresExpr(has(requiresExprBodyDecl()))))); } +TEST_P(ImportExpr, ImportSubstNonTypeTemplateParmPackExpr) { + MatchVerifier<Decl> Verifier; + const char *Code = R"( + template<auto ...> struct X {}; + template<typename ...> struct Z {}; + + template<int ...N> struct E { + template<int ...M> using B = Z<X<N, M>...>; + template<int M1, int M2> E(B<M1, M2>); + }; + using declToImport = E<1, 3>; + )"; + testImport(Code, Lang_CXX20, "", Lang_CXX20, Verifier, + typedefNameDecl(hasName("declToImport"))); +} + +TEST_P(ImportExpr, ImportCXXParenListInitExpr) { + MatchVerifier<Decl> Verifier; + const char *Code = R"( + struct Node { + int val; + double d; + }; + Node* declToImport() { return new Node(2, 3.14); } + )"; + testImport(Code, Lang_CXX20, "", Lang_CXX20, Verifier, + functionDecl(hasName("declToImport"))); +} + +TEST_P(ImportExpr, ImportPseudoObjectExpr) { + MatchVerifier<Decl> Verifier; + const char *Code = R"( + namespace std { + struct strong_ordering { + int n; + constexpr operator int() const { return n; } + static const strong_ordering less, equal, greater; + }; + constexpr strong_ordering strong_ordering::less{-1}, + strong_ordering::equal{0}, strong_ordering::greater{1}; + } + + struct A { + std::strong_ordering operator<=>(const A&) const; + }; + struct B { + bool operator==(const B&) const; + bool operator<(const B&) const; + }; + + template<typename T> struct Cmp : T { + std::strong_ordering operator<=>(const Cmp&) const = default; + }; + + void use(...); + void declToImport() { + use( + Cmp<A>() <=> Cmp<A>(), + Cmp<B>() <=> Cmp<B>() + ); + } + )"; + testImport(Code, Lang_CXX20, "", Lang_CXX20, Verifier, + functionDecl(hasName("declToImport"))); +} + class ImportImplicitMethods : public ASTImporterOptionSpecificTestBase { public: static constexpr auto DefaultCode = R"( diff --git a/clang/unittests/AST/TypePrinterTest.cpp b/clang/unittests/AST/TypePrinterTest.cpp index ca0380b..3cadf9b 100644 --- a/clang/unittests/AST/TypePrinterTest.cpp +++ b/clang/unittests/AST/TypePrinterTest.cpp @@ -295,3 +295,68 @@ TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) { Ctx, Arg, Param, ArgList.asArray(), Params->getDepth())); } } + +TEST(TypePrinter, NestedNameSpecifiers) { + constexpr char Code[] = R"cpp( + void level1() { + struct Inner { + Inner(int) { + struct { + union {} u; + } imem; + } + }; + } + )cpp"; + + // Types scoped immediately inside a function don't print the function name in + // their scope. + ASSERT_TRUE(PrintedTypeMatches( + Code, {}, varDecl(hasName("imem"), hasType(qualType().bind("id"))), + "struct (unnamed)", [](PrintingPolicy &Policy) { + Policy.FullyQualifiedName = true; + Policy.AnonymousTagLocations = false; + })); + + ASSERT_TRUE(PrintedTypeMatches( + Code, {}, varDecl(hasName("imem"), hasType(qualType().bind("id"))), + "struct (unnamed)", [](PrintingPolicy &Policy) { + Policy.FullyQualifiedName = false; + Policy.AnonymousTagLocations = false; + })); + + // Further levels of nesting print the entire scope. + ASSERT_TRUE(PrintedTypeMatches( + Code, {}, fieldDecl(hasName("u"), hasType(qualType().bind("id"))), + "union level1()::Inner::Inner(int)::(anonymous struct)::(unnamed)", + [](PrintingPolicy &Policy) { + Policy.FullyQualifiedName = true; + Policy.AnonymousTagLocations = false; + })); + + ASSERT_TRUE(PrintedTypeMatches( + Code, {}, fieldDecl(hasName("u"), hasType(qualType().bind("id"))), + "union (unnamed)", [](PrintingPolicy &Policy) { + Policy.FullyQualifiedName = false; + Policy.AnonymousTagLocations = false; + })); +} + +TEST(TypePrinter, NestedNameSpecifiersTypedef) { + constexpr char Code[] = R"cpp( + typedef union { + struct { + struct { + unsigned int baz; + } bar; + }; + } foo; + )cpp"; + + ASSERT_TRUE(PrintedTypeMatches( + Code, {}, fieldDecl(hasName("bar"), hasType(qualType().bind("id"))), + "struct foo::(anonymous struct)::(unnamed)", [](PrintingPolicy &Policy) { + Policy.FullyQualifiedName = true; + Policy.AnonymousTagLocations = false; + })); +} |
