aboutsummaryrefslogtreecommitdiff
path: root/clang/unittests/AST
diff options
context:
space:
mode:
Diffstat (limited to 'clang/unittests/AST')
-rw-r--r--clang/unittests/AST/ASTImporterTest.cpp117
-rw-r--r--clang/unittests/AST/TypePrinterTest.cpp65
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;
+ }));
+}