1 //===- unittests/AST/EvaluateAsRValueTest.cpp -----------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // \file 11 // \brief Unit tests for evaluation of constant initializers. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include <map> 16 #include <string> 17 18 #include "clang/AST/ASTConsumer.h" 19 #include "clang/AST/ASTContext.h" 20 #include "clang/AST/RecursiveASTVisitor.h" 21 #include "clang/Tooling/Tooling.h" 22 #include "gtest/gtest.h" 23 24 #include "clang/AST/ASTConsumer.h" 25 26 using namespace clang::tooling; 27 28 namespace { 29 // For each variable name encountered, whether its initializer was a 30 // constant. 31 typedef std::map<std::string, bool> VarInfoMap; 32 33 /// \brief Records information on variable initializers to a map. 34 class EvaluateConstantInitializersVisitor 35 : public clang::RecursiveASTVisitor<EvaluateConstantInitializersVisitor> { 36 public: 37 explicit EvaluateConstantInitializersVisitor(VarInfoMap &VarInfo) 38 : VarInfo(VarInfo) {} 39 40 /// \brief Checks that isConstantInitializer and EvaluateAsRValue agree 41 /// and don't crash. 42 /// 43 /// For each VarDecl with an initializer this also records in VarInfo 44 /// whether the initializer could be evaluated as a constant. 45 bool VisitVarDecl(const clang::VarDecl *VD) { 46 if (const clang::Expr *Init = VD->getInit()) { 47 clang::Expr::EvalResult Result; 48 bool WasEvaluated = Init->EvaluateAsRValue(Result, VD->getASTContext()); 49 VarInfo[VD->getNameAsString()] = WasEvaluated; 50 EXPECT_EQ(WasEvaluated, Init->isConstantInitializer(VD->getASTContext(), 51 false /*ForRef*/)); 52 } 53 return true; 54 } 55 56 private: 57 VarInfoMap &VarInfo; 58 }; 59 60 class EvaluateConstantInitializersAction : public clang::ASTFrontendAction { 61 public: 62 clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &Compiler, 63 llvm::StringRef FilePath) override { 64 return new Consumer; 65 } 66 67 private: 68 class Consumer : public clang::ASTConsumer { 69 public: 70 ~Consumer() override {} 71 72 void HandleTranslationUnit(clang::ASTContext &Ctx) override { 73 VarInfoMap VarInfo; 74 EvaluateConstantInitializersVisitor Evaluator(VarInfo); 75 Evaluator.TraverseDecl(Ctx.getTranslationUnitDecl()); 76 EXPECT_EQ(2u, VarInfo.size()); 77 EXPECT_FALSE(VarInfo["Dependent"]); 78 EXPECT_TRUE(VarInfo["Constant"]); 79 EXPECT_EQ(2u, VarInfo.size()); 80 } 81 }; 82 }; 83 } 84 85 TEST(EvaluateAsRValue, FailsGracefullyForUnknownTypes) { 86 // This is a regression test; the AST library used to trigger assertion 87 // failures because it assumed that the type of initializers was always 88 // known (which is true only after template instantiation). 89 std::string ModesToTest[] = {"-std=c++03", "-std=c++11", "-std=c++1y"}; 90 for (std::string const &Mode : ModesToTest) { 91 std::vector<std::string> Args(1, Mode); 92 Args.push_back("-fno-delayed-template-parsing"); 93 ASSERT_TRUE(runToolOnCodeWithArgs( 94 new EvaluateConstantInitializersAction(), 95 "template <typename T>" 96 "struct vector {" 97 " explicit vector(int size);" 98 "};" 99 "template <typename R>" 100 "struct S {" 101 " vector<R> intervals() const {" 102 " vector<R> Dependent(2);" 103 " return Dependent;" 104 " }" 105 "};" 106 "void doSomething() {" 107 " int Constant = 2 + 2;" 108 " (void) Constant;" 109 "}", 110 Args)); 111 } 112 } 113