1 //===- unittests/AST/EvaluateAsRValueTest.cpp -----------------------------===//
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
7 //===----------------------------------------------------------------------===//
10 // \brief Unit tests for evaluation of constant initializers.
12 //===----------------------------------------------------------------------===//
14 #include "clang/AST/ASTConsumer.h"
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/RecursiveASTVisitor.h"
17 #include "clang/Tooling/Tooling.h"
18 #include "gtest/gtest.h"
22 using namespace clang::tooling
;
25 // For each variable name encountered, whether its initializer was a
27 typedef std::map
<std::string
, bool> VarInfoMap
;
29 /// \brief Records information on variable initializers to a map.
30 class EvaluateConstantInitializersVisitor
31 : public clang::RecursiveASTVisitor
<EvaluateConstantInitializersVisitor
> {
33 explicit EvaluateConstantInitializersVisitor(VarInfoMap
&VarInfo
)
36 /// \brief Checks that isConstantInitializer and EvaluateAsRValue agree
39 /// For each VarDecl with an initializer this also records in VarInfo
40 /// whether the initializer could be evaluated as a constant.
41 bool VisitVarDecl(const clang::VarDecl
*VD
) {
42 if (const clang::Expr
*Init
= VD
->getInit()) {
43 clang::Expr::EvalResult Result
;
44 bool WasEvaluated
= Init
->EvaluateAsRValue(Result
, VD
->getASTContext());
45 VarInfo
[VD
->getNameAsString()] = WasEvaluated
;
46 EXPECT_EQ(WasEvaluated
, Init
->isConstantInitializer(VD
->getASTContext(),
56 class EvaluateConstantInitializersAction
: public clang::ASTFrontendAction
{
58 std::unique_ptr
<clang::ASTConsumer
>
59 CreateASTConsumer(clang::CompilerInstance
&Compiler
,
60 llvm::StringRef FilePath
) override
{
61 return std::make_unique
<Consumer
>();
65 class Consumer
: public clang::ASTConsumer
{
67 ~Consumer() override
{}
69 void HandleTranslationUnit(clang::ASTContext
&Ctx
) override
{
71 EvaluateConstantInitializersVisitor
Evaluator(VarInfo
);
72 Evaluator
.TraverseDecl(Ctx
.getTranslationUnitDecl());
73 EXPECT_EQ(2u, VarInfo
.size());
74 EXPECT_FALSE(VarInfo
["Dependent"]);
75 EXPECT_TRUE(VarInfo
["Constant"]);
76 EXPECT_EQ(2u, VarInfo
.size());
82 TEST(EvaluateAsRValue
, FailsGracefullyForUnknownTypes
) {
83 // This is a regression test; the AST library used to trigger assertion
84 // failures because it assumed that the type of initializers was always
85 // known (which is true only after template instantiation).
86 std::string ModesToTest
[] = {"-std=c++03", "-std=c++11", "-std=c++1y"};
87 for (std::string
const &Mode
: ModesToTest
) {
88 std::vector
<std::string
> Args(1, Mode
);
89 Args
.push_back("-fno-delayed-template-parsing");
90 ASSERT_TRUE(runToolOnCodeWithArgs(
91 std::make_unique
<EvaluateConstantInitializersAction
>(),
92 "template <typename T>"
94 " explicit vector(int size);"
96 "template <typename R>"
98 " vector<R> intervals() const {"
99 " vector<R> Dependent(2);"
103 "void doSomething() {"
104 " int Constant = 2 + 2;"
111 class CheckLValueToRValueConversionVisitor
112 : public clang::RecursiveASTVisitor
<CheckLValueToRValueConversionVisitor
> {
114 bool VisitDeclRefExpr(const clang::DeclRefExpr
*E
) {
115 clang::Expr::EvalResult Result
;
116 E
->EvaluateAsRValue(Result
, E
->getDecl()->getASTContext(), true);
118 EXPECT_TRUE(Result
.Val
.hasValue());
119 // Since EvaluateAsRValue does an implicit lvalue-to-rvalue conversion,
120 // the result cannot be a LValue.
121 EXPECT_FALSE(Result
.Val
.isLValue());
127 class CheckConversionAction
: public clang::ASTFrontendAction
{
129 std::unique_ptr
<clang::ASTConsumer
>
130 CreateASTConsumer(clang::CompilerInstance
&Compiler
,
131 llvm::StringRef FilePath
) override
{
132 return std::make_unique
<Consumer
>();
136 class Consumer
: public clang::ASTConsumer
{
138 ~Consumer() override
{}
140 void HandleTranslationUnit(clang::ASTContext
&Ctx
) override
{
141 CheckLValueToRValueConversionVisitor Evaluator
;
142 Evaluator
.TraverseDecl(Ctx
.getTranslationUnitDecl());
147 TEST(EvaluateAsRValue
, LValueToRValueConversionWorks
) {
148 std::string ModesToTest
[] = {"", "-fexperimental-new-constant-interpreter"};
149 for (std::string
const &Mode
: ModesToTest
) {
150 std::vector
<std::string
> Args(1, Mode
);
151 ASSERT_TRUE(runToolOnCodeWithArgs(std::make_unique
<CheckConversionAction
>(),
152 "constexpr int a = 20;\n"
153 "static_assert(a == 20, \"\");\n",