Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / unittests / AST / EvaluateAsRValueTest.cpp
blobf6261b827671bce8feda3c0b41bf87e648692f64
1 //===- unittests/AST/EvaluateAsRValueTest.cpp -----------------------------===//
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 // \file
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"
19 #include <map>
20 #include <string>
22 using namespace clang::tooling;
24 namespace {
25 // For each variable name encountered, whether its initializer was a
26 // constant.
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> {
32 public:
33 explicit EvaluateConstantInitializersVisitor(VarInfoMap &VarInfo)
34 : VarInfo(VarInfo) {}
36 /// \brief Checks that isConstantInitializer and EvaluateAsRValue agree
37 /// and don't crash.
38 ///
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(),
47 false /*ForRef*/));
49 return true;
52 private:
53 VarInfoMap &VarInfo;
56 class EvaluateConstantInitializersAction : public clang::ASTFrontendAction {
57 public:
58 std::unique_ptr<clang::ASTConsumer>
59 CreateASTConsumer(clang::CompilerInstance &Compiler,
60 llvm::StringRef FilePath) override {
61 return std::make_unique<Consumer>();
64 private:
65 class Consumer : public clang::ASTConsumer {
66 public:
67 ~Consumer() override {}
69 void HandleTranslationUnit(clang::ASTContext &Ctx) override {
70 VarInfoMap VarInfo;
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>"
93 "struct vector {"
94 " explicit vector(int size);"
95 "};"
96 "template <typename R>"
97 "struct S {"
98 " vector<R> intervals() const {"
99 " vector<R> Dependent(2);"
100 " return Dependent;"
101 " }"
102 "};"
103 "void doSomething() {"
104 " int Constant = 2 + 2;"
105 " (void) Constant;"
106 "}",
107 Args));
111 class CheckLValueToRValueConversionVisitor
112 : public clang::RecursiveASTVisitor<CheckLValueToRValueConversionVisitor> {
113 public:
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());
123 return true;
127 class CheckConversionAction : public clang::ASTFrontendAction {
128 public:
129 std::unique_ptr<clang::ASTConsumer>
130 CreateASTConsumer(clang::CompilerInstance &Compiler,
131 llvm::StringRef FilePath) override {
132 return std::make_unique<Consumer>();
135 private:
136 class Consumer : public clang::ASTConsumer {
137 public:
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",
154 Args));