xref: /llvm-project/clang/unittests/AST/DeclTest.cpp (revision f85a6a812718cfdaeb1d0dc971ce3875aa82fafe)
1 //===- unittests/AST/DeclTest.cpp --- Declaration tests -------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Unit tests for Decl nodes in the AST.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "clang/AST/Decl.h"
14 #include "clang/AST/ASTContext.h"
15 #include "clang/AST/Mangle.h"
16 #include "clang/ASTMatchers/ASTMatchFinder.h"
17 #include "clang/ASTMatchers/ASTMatchers.h"
18 #include "clang/Basic/LLVM.h"
19 #include "clang/Basic/TargetInfo.h"
20 #include "clang/Lex/Lexer.h"
21 #include "clang/Tooling/Tooling.h"
22 #include "llvm/IR/DataLayout.h"
23 #include "llvm/Testing/Support/Annotations.h"
24 #include "gtest/gtest.h"
25 
26 using namespace clang::ast_matchers;
27 using namespace clang::tooling;
28 using namespace clang;
29 
30 TEST(Decl, CleansUpAPValues) {
31   MatchFinder Finder;
32   std::unique_ptr<FrontendActionFactory> Factory(
33       newFrontendActionFactory(&Finder));
34 
35   // This is a regression test for a memory leak in APValues for structs that
36   // allocate memory. This test only fails if run under valgrind with full leak
37   // checking enabled.
38   std::vector<std::string> Args(1, "-std=c++11");
39   Args.push_back("-fno-ms-extensions");
40   ASSERT_TRUE(runToolOnCodeWithArgs(
41       Factory->create(),
42       "struct X { int a; }; constexpr X x = { 42 };"
43       "union Y { constexpr Y(int a) : a(a) {} int a; }; constexpr Y y = { 42 };"
44       "constexpr int z[2] = { 42, 43 };"
45       "constexpr int __attribute__((vector_size(16))) v1 = {};"
46       "\n#ifdef __SIZEOF_INT128__\n"
47       "constexpr __uint128_t large_int = 0xffffffffffffffff;"
48       "constexpr __uint128_t small_int = 1;"
49       "\n#endif\n"
50       "constexpr double d1 = 42.42;"
51       "constexpr long double d2 = 42.42;"
52       "constexpr _Complex long double c1 = 42.0i;"
53       "constexpr _Complex long double c2 = 42.0;"
54       "template<int N> struct A : A<N-1> {};"
55       "template<> struct A<0> { int n; }; A<50> a;"
56       "constexpr int &r = a.n;"
57       "constexpr int A<50>::*p = &A<50>::n;"
58       "void f() { foo: bar: constexpr int k = __builtin_constant_p(0) ?"
59       "                         (char*)&&foo - (char*)&&bar : 0; }",
60       Args));
61 
62   // FIXME: Once this test starts breaking we can test APValue::needsCleanup
63   // for ComplexInt.
64   ASSERT_FALSE(runToolOnCodeWithArgs(
65       Factory->create(),
66       "constexpr _Complex __uint128_t c = 0xffffffffffffffff;",
67       Args));
68 }
69 
70 TEST(Decl, AsmLabelAttr) {
71   // Create two method decls: `f` and `g`.
72   StringRef Code = R"(
73     struct S {
74       void f() {}
75       void g() {}
76     };
77   )";
78   auto AST =
79       tooling::buildASTFromCodeWithArgs(Code, {"-target", "i386-apple-darwin"});
80   ASTContext &Ctx = AST->getASTContext();
81   assert(Ctx.getTargetInfo().getUserLabelPrefix() == StringRef("_") &&
82          "Expected target to have a global prefix");
83   DiagnosticsEngine &Diags = AST->getDiagnostics();
84 
85   const auto *DeclS =
86       selectFirst<CXXRecordDecl>("d", match(cxxRecordDecl().bind("d"), Ctx));
87   NamedDecl *DeclF = *DeclS->method_begin();
88   NamedDecl *DeclG = *(++DeclS->method_begin());
89 
90   // Attach asm labels to the decls: one literal, and one not.
91   DeclF->addAttr(::new (Ctx) AsmLabelAttr(Ctx, SourceLocation(), "foo",
92                                           /*LiteralLabel=*/true));
93   DeclG->addAttr(::new (Ctx) AsmLabelAttr(Ctx, SourceLocation(), "goo",
94                                           /*LiteralLabel=*/false));
95 
96   // Mangle the decl names.
97   std::string MangleF, MangleG;
98   std::unique_ptr<ItaniumMangleContext> MC(
99       ItaniumMangleContext::create(Ctx, Diags));
100   {
101     llvm::raw_string_ostream OS_F(MangleF);
102     llvm::raw_string_ostream OS_G(MangleG);
103     MC->mangleName(DeclF, OS_F);
104     MC->mangleName(DeclG, OS_G);
105   }
106 
107   ASSERT_TRUE(0 == MangleF.compare("\x01" "foo"));
108   ASSERT_TRUE(0 == MangleG.compare("goo"));
109 }
110 
111 TEST(Decl, MangleDependentSizedArray) {
112   StringRef Code = R"(
113     template <int ...N>
114     int A[] = {N...};
115 
116     template <typename T, int N>
117     struct S {
118       T B[N];
119     };
120   )";
121   auto AST =
122       tooling::buildASTFromCodeWithArgs(Code, {"-target", "i386-apple-darwin"});
123   ASTContext &Ctx = AST->getASTContext();
124   assert(Ctx.getTargetInfo().getUserLabelPrefix() == StringRef("_") &&
125          "Expected target to have a global prefix");
126   DiagnosticsEngine &Diags = AST->getDiagnostics();
127 
128   const auto *DeclA =
129       selectFirst<VarDecl>("A", match(varDecl().bind("A"), Ctx));
130   const auto *DeclB =
131       selectFirst<FieldDecl>("B", match(fieldDecl().bind("B"), Ctx));
132 
133   std::string MangleA, MangleB;
134   llvm::raw_string_ostream OS_A(MangleA), OS_B(MangleB);
135   std::unique_ptr<ItaniumMangleContext> MC(
136       ItaniumMangleContext::create(Ctx, Diags));
137 
138   MC->mangleTypeName(DeclA->getType(), OS_A);
139   MC->mangleTypeName(DeclB->getType(), OS_B);
140 
141   ASSERT_TRUE(0 == MangleA.compare("_ZTSA_i"));
142   ASSERT_TRUE(0 == MangleB.compare("_ZTSAT0__T_"));
143 }
144 
145 TEST(Decl, EnumDeclRange) {
146   llvm::Annotations Code(R"(
147     typedef int Foo;
148     [[enum Bar : Foo]];)");
149   auto AST = tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{});
150   ASTContext &Ctx = AST->getASTContext();
151   const auto &SM = Ctx.getSourceManager();
152 
153   const auto *Bar =
154       selectFirst<TagDecl>("Bar", match(enumDecl().bind("Bar"), Ctx));
155   auto BarRange =
156       Lexer::getAsCharRange(Bar->getSourceRange(), SM, Ctx.getLangOpts());
157   EXPECT_EQ(SM.getFileOffset(BarRange.getBegin()), Code.range().Begin);
158   EXPECT_EQ(SM.getFileOffset(BarRange.getEnd()), Code.range().End);
159 }
160 
161 TEST(Decl, IsInExportDeclContext) {
162   llvm::Annotations Code(R"(
163     export module m;
164     export template <class T>
165     void f() {})");
166   auto AST =
167       tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{"-std=c++20"});
168   ASTContext &Ctx = AST->getASTContext();
169 
170   const auto *f =
171       selectFirst<FunctionDecl>("f", match(functionDecl().bind("f"), Ctx));
172   EXPECT_TRUE(f->isInExportDeclContext());
173 }
174