xref: /llvm-project/clang/unittests/AST/DeclTest.cpp (revision d54888a3ebb141cdbb5e88ed7a3a2a54d24fc904)
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/Annotations/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 
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 
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"});
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(), InternalLinkage);
254   EXPECT_EQ(f->getLinkageInternal(), InternalLinkage);
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 
264 TEST(Decl, GetNonTransparentDeclContext) {
265   llvm::Annotations Code(R"(
266     export module m3;
267     export template <class> struct X {
268       template <class Self> friend void f(Self &&self) {
269         (Self&)self;
270       }
271     };)");
272 
273   auto AST =
274       tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{"-std=c++20"});
275   ASTContext &Ctx = AST->getASTContext();
276 
277   auto *f = selectFirst<FunctionDecl>(
278       "f", match(functionDecl(hasName("f")).bind("f"), Ctx));
279 
280   EXPECT_TRUE(f->getNonTransparentDeclContext()->isFileContext());
281 }
282 
283 TEST(Decl, MemberFunctionInModules) {
284   llvm::Annotations Code(R"(
285     module;
286     class G {
287       void bar() {}
288     };
289     export module M;
290     class A {
291       void foo() {}
292     };
293     )");
294 
295   auto AST =
296       tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{"-std=c++20"});
297   ASTContext &Ctx = AST->getASTContext();
298 
299   auto *foo = selectFirst<FunctionDecl>(
300       "foo", match(functionDecl(hasName("foo")).bind("foo"), Ctx));
301 
302   // The function defined within a class definition is not implicitly inline
303   // if it is not attached to global module
304   EXPECT_FALSE(foo->isInlined());
305 
306   auto *bar = selectFirst<FunctionDecl>(
307       "bar", match(functionDecl(hasName("bar")).bind("bar"), Ctx));
308 
309   // In global module, the function defined within a class definition is
310   // implicitly inline.
311   EXPECT_TRUE(bar->isInlined());
312 }
313 
314 TEST(Decl, MemberFunctionInHeaderUnit) {
315   llvm::Annotations Code(R"(
316     class foo {
317     public:
318       int memFn() {
319         return 43;
320       }
321     };
322     )");
323 
324   auto AST = tooling::buildASTFromCodeWithArgs(
325       Code.code(), {"-std=c++20", " -xc++-user-header ", "-emit-header-unit"});
326   ASTContext &Ctx = AST->getASTContext();
327 
328   auto *memFn = selectFirst<FunctionDecl>(
329       "memFn", match(functionDecl(hasName("memFn")).bind("memFn"), Ctx));
330 
331   EXPECT_TRUE(memFn->isInlined());
332 }
333 
334 TEST(Decl, FriendFunctionWithinClassInHeaderUnit) {
335   llvm::Annotations Code(R"(
336     class foo {
337       int value;
338     public:
339       foo(int v) : value(v) {}
340 
341       friend int getFooValue(foo f) {
342         return f.value;
343       }
344     };
345     )");
346 
347   auto AST = tooling::buildASTFromCodeWithArgs(
348       Code.code(), {"-std=c++20", " -xc++-user-header ", "-emit-header-unit"});
349   ASTContext &Ctx = AST->getASTContext();
350 
351   auto *getFooValue = selectFirst<FunctionDecl>(
352       "getFooValue",
353       match(functionDecl(hasName("getFooValue")).bind("getFooValue"), Ctx));
354 
355   EXPECT_TRUE(getFooValue->isInlined());
356 }
357 
358 TEST(Decl, NoProtoFunctionDeclAttributes) {
359   llvm::Annotations Code(R"(
360     void f();
361     )");
362 
363   auto AST = tooling::buildASTFromCodeWithArgs(
364       Code.code(),
365       /*Args=*/{"-target", "i386-apple-darwin", "-x", "objective-c",
366                 "-std=c89"});
367   ASTContext &Ctx = AST->getASTContext();
368 
369   auto *f = selectFirst<FunctionDecl>(
370       "f", match(functionDecl(hasName("f")).bind("f"), Ctx));
371 
372   const auto *FPT = f->getType()->getAs<FunctionNoProtoType>();
373 
374   // Functions without prototypes always have 0 initialized qualifiers
375   EXPECT_FALSE(FPT->isConst());
376   EXPECT_FALSE(FPT->isVolatile());
377   EXPECT_FALSE(FPT->isRestrict());
378 }
379 
380 TEST(Decl, ImplicitlyDeclaredAllocationFunctionsInModules) {
381   // C++ [basic.stc.dynamic.general]p2:
382   //   The library provides default definitions for the global allocation
383   //   and deallocation functions. Some global allocation and deallocation
384   //   functions are replaceable ([new.delete]); these are attached to the
385   //   global module ([module.unit]).
386 
387   llvm::Annotations Code(R"(
388     export module base;
389 
390     export struct Base {
391         virtual void hello() = 0;
392         virtual ~Base() = default;
393     };
394   )");
395 
396   auto AST =
397       tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{"-std=c++20"});
398   ASTContext &Ctx = AST->getASTContext();
399 
400   // void* operator new(std::size_t);
401   auto *SizedOperatorNew = selectFirst<FunctionDecl>(
402       "operator new",
403       match(functionDecl(hasName("operator new"), parameterCountIs(1),
404                          hasParameter(0, hasType(isUnsignedInteger())))
405                 .bind("operator new"),
406             Ctx));
407   ASSERT_TRUE(SizedOperatorNew->getOwningModule());
408   EXPECT_TRUE(SizedOperatorNew->getOwningModule()->isGlobalModule());
409 
410   // void* operator new(std::size_t, std::align_val_t);
411   auto *SizedAlignedOperatorNew = selectFirst<FunctionDecl>(
412       "operator new",
413       match(functionDecl(
414                 hasName("operator new"), parameterCountIs(2),
415                 hasParameter(0, hasType(isUnsignedInteger())),
416                 hasParameter(1, hasType(enumDecl(hasName("std::align_val_t")))))
417                 .bind("operator new"),
418             Ctx));
419   ASSERT_TRUE(SizedAlignedOperatorNew->getOwningModule());
420   EXPECT_TRUE(SizedAlignedOperatorNew->getOwningModule()->isGlobalModule());
421 
422   // void* operator new[](std::size_t);
423   auto *SizedArrayOperatorNew = selectFirst<FunctionDecl>(
424       "operator new[]",
425       match(functionDecl(hasName("operator new[]"), parameterCountIs(1),
426                          hasParameter(0, hasType(isUnsignedInteger())))
427                 .bind("operator new[]"),
428             Ctx));
429   ASSERT_TRUE(SizedArrayOperatorNew->getOwningModule());
430   EXPECT_TRUE(SizedArrayOperatorNew->getOwningModule()->isGlobalModule());
431 
432   // void* operator new[](std::size_t, std::align_val_t);
433   auto *SizedAlignedArrayOperatorNew = selectFirst<FunctionDecl>(
434       "operator new[]",
435       match(functionDecl(
436                 hasName("operator new[]"), parameterCountIs(2),
437                 hasParameter(0, hasType(isUnsignedInteger())),
438                 hasParameter(1, hasType(enumDecl(hasName("std::align_val_t")))))
439                 .bind("operator new[]"),
440             Ctx));
441   ASSERT_TRUE(SizedAlignedArrayOperatorNew->getOwningModule());
442   EXPECT_TRUE(
443       SizedAlignedArrayOperatorNew->getOwningModule()->isGlobalModule());
444 
445   // void operator delete(void*) noexcept;
446   auto *Delete = selectFirst<FunctionDecl>(
447       "operator delete",
448       match(functionDecl(
449                 hasName("operator delete"), parameterCountIs(1),
450                 hasParameter(0, hasType(pointerType(pointee(voidType())))))
451                 .bind("operator delete"),
452             Ctx));
453   ASSERT_TRUE(Delete->getOwningModule());
454   EXPECT_TRUE(Delete->getOwningModule()->isGlobalModule());
455 
456   // void operator delete(void*, std::align_val_t) noexcept;
457   auto *AlignedDelete = selectFirst<FunctionDecl>(
458       "operator delete",
459       match(functionDecl(
460                 hasName("operator delete"), parameterCountIs(2),
461                 hasParameter(0, hasType(pointerType(pointee(voidType())))),
462                 hasParameter(1, hasType(enumDecl(hasName("std::align_val_t")))))
463                 .bind("operator delete"),
464             Ctx));
465   ASSERT_TRUE(AlignedDelete->getOwningModule());
466   EXPECT_TRUE(AlignedDelete->getOwningModule()->isGlobalModule());
467 
468   // Sized deallocation is not enabled by default. So we skip it here.
469 
470   // void operator delete[](void*) noexcept;
471   auto *ArrayDelete = selectFirst<FunctionDecl>(
472       "operator delete[]",
473       match(functionDecl(
474                 hasName("operator delete[]"), parameterCountIs(1),
475                 hasParameter(0, hasType(pointerType(pointee(voidType())))))
476                 .bind("operator delete[]"),
477             Ctx));
478   ASSERT_TRUE(ArrayDelete->getOwningModule());
479   EXPECT_TRUE(ArrayDelete->getOwningModule()->isGlobalModule());
480 
481   // void operator delete[](void*, std::align_val_t) noexcept;
482   auto *AlignedArrayDelete = selectFirst<FunctionDecl>(
483       "operator delete[]",
484       match(functionDecl(
485                 hasName("operator delete[]"), parameterCountIs(2),
486                 hasParameter(0, hasType(pointerType(pointee(voidType())))),
487                 hasParameter(1, hasType(enumDecl(hasName("std::align_val_t")))))
488                 .bind("operator delete[]"),
489             Ctx));
490   ASSERT_TRUE(AlignedArrayDelete->getOwningModule());
491   EXPECT_TRUE(AlignedArrayDelete->getOwningModule()->isGlobalModule());
492 }
493 
494 TEST(Decl, TemplateArgumentDefaulted) {
495   llvm::Annotations Code(R"cpp(
496     template<typename T1, typename T2>
497     struct Alloc {};
498 
499     template <typename T1,
500               typename T2 = double,
501               int      T3 = 42,
502               typename T4 = Alloc<T1, T2>>
503     struct Foo {
504     };
505 
506     Foo<char, int, 42, Alloc<char, int>> X;
507   )cpp");
508 
509   auto AST =
510       tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{"-std=c++20"});
511   ASTContext &Ctx = AST->getASTContext();
512 
513   auto const *CTSD = selectFirst<ClassTemplateSpecializationDecl>(
514       "id",
515       match(classTemplateSpecializationDecl(hasName("Foo")).bind("id"), Ctx));
516   ASSERT_NE(CTSD, nullptr);
517   auto const &ArgList = CTSD->getTemplateArgs();
518 
519   EXPECT_FALSE(ArgList.get(0).getIsDefaulted());
520   EXPECT_FALSE(ArgList.get(1).getIsDefaulted());
521   EXPECT_TRUE(ArgList.get(2).getIsDefaulted());
522   EXPECT_TRUE(ArgList.get(3).getIsDefaulted());
523 }
524