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
TEST(Decl,CleansUpAPValues)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
TEST(Decl,AsmLabelAttr)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
TEST(Decl,MangleDependentSizedArray)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
TEST(Decl,EnumDeclRange)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
TEST(Decl,IsInExportDeclContext)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
TEST(Decl,InConsistLinkageForTemplates)175 TEST(Decl, InConsistLinkageForTemplates) {
176 llvm::Annotations Code(R"(
177 export module m;
178 export template <class T>
179 void f() {}
180
181 template <>
182 void f<int>() {}
183
184 export template <class T>
185 class C {};
186
187 template<>
188 class C<int> {};
189 )");
190
191 auto AST =
192 tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{"-std=c++20"});
193 ASTContext &Ctx = AST->getASTContext();
194
195 llvm::SmallVector<ast_matchers::BoundNodes, 2> Funcs =
196 match(functionDecl().bind("f"), Ctx);
197
198 EXPECT_EQ(Funcs.size(), 2U);
199 const FunctionDecl *TemplateF = Funcs[0].getNodeAs<FunctionDecl>("f");
200 const FunctionDecl *SpecializedF = Funcs[1].getNodeAs<FunctionDecl>("f");
201 EXPECT_EQ(TemplateF->getLinkageInternal(),
202 SpecializedF->getLinkageInternal());
203
204 llvm::SmallVector<ast_matchers::BoundNodes, 1> ClassTemplates =
205 match(classTemplateDecl().bind("C"), Ctx);
206 llvm::SmallVector<ast_matchers::BoundNodes, 1> ClassSpecializations =
207 match(classTemplateSpecializationDecl().bind("C"), Ctx);
208
209 EXPECT_EQ(ClassTemplates.size(), 1U);
210 EXPECT_EQ(ClassSpecializations.size(), 1U);
211 const NamedDecl *TemplatedC = ClassTemplates[0].getNodeAs<NamedDecl>("C");
212 const NamedDecl *SpecializedC = ClassSpecializations[0].getNodeAs<NamedDecl>("C");
213 EXPECT_EQ(TemplatedC->getLinkageInternal(),
214 SpecializedC->getLinkageInternal());
215 }
216
TEST(Decl,ModuleAndInternalLinkage)217 TEST(Decl, ModuleAndInternalLinkage) {
218 llvm::Annotations Code(R"(
219 export module M;
220 static int a;
221 static int f(int x);
222
223 int b;
224 int g(int x);)");
225
226 auto AST =
227 tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{"-std=c++20"});
228 ASTContext &Ctx = AST->getASTContext();
229
230 const auto *a =
231 selectFirst<VarDecl>("a", match(varDecl(hasName("a")).bind("a"), Ctx));
232 const auto *f = selectFirst<FunctionDecl>(
233 "f", match(functionDecl(hasName("f")).bind("f"), Ctx));
234
235 EXPECT_EQ(a->getLinkageInternal(), InternalLinkage);
236 EXPECT_EQ(f->getLinkageInternal(), InternalLinkage);
237
238 const auto *b =
239 selectFirst<VarDecl>("b", match(varDecl(hasName("b")).bind("b"), Ctx));
240 const auto *g = selectFirst<FunctionDecl>(
241 "g", match(functionDecl(hasName("g")).bind("g"), Ctx));
242
243 EXPECT_EQ(b->getLinkageInternal(), ModuleLinkage);
244 EXPECT_EQ(g->getLinkageInternal(), ModuleLinkage);
245
246 AST = tooling::buildASTFromCodeWithArgs(
247 Code.code(), /*Args=*/{"-std=c++20", "-fmodules-ts"});
248 ASTContext &CtxTS = AST->getASTContext();
249 a = selectFirst<VarDecl>("a", match(varDecl(hasName("a")).bind("a"), CtxTS));
250 f = selectFirst<FunctionDecl>(
251 "f", match(functionDecl(hasName("f")).bind("f"), CtxTS));
252
253 EXPECT_EQ(a->getLinkageInternal(), ModuleInternalLinkage);
254 EXPECT_EQ(f->getLinkageInternal(), ModuleInternalLinkage);
255
256 b = selectFirst<VarDecl>("b", match(varDecl(hasName("b")).bind("b"), CtxTS));
257 g = selectFirst<FunctionDecl>(
258 "g", match(functionDecl(hasName("g")).bind("g"), CtxTS));
259
260 EXPECT_EQ(b->getLinkageInternal(), ModuleLinkage);
261 EXPECT_EQ(g->getLinkageInternal(), ModuleLinkage);
262 }
263