brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.1 KiB · 1e17330 Raw
157 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// \file10// \brief Unit tests for evaluation of constant initializers.11//12//===----------------------------------------------------------------------===//13 14#include "clang/AST/ASTConsumer.h"15#include "clang/AST/ASTContext.h"16#include "clang/AST/DynamicRecursiveASTVisitor.h"17#include "clang/Tooling/Tooling.h"18#include "gtest/gtest.h"19#include <map>20#include <string>21 22using namespace clang::tooling;23 24namespace {25// For each variable name encountered, whether its initializer was a26// constant.27typedef std::map<std::string, bool> VarInfoMap;28 29/// \brief Records information on variable initializers to a map.30class EvaluateConstantInitializersVisitor31    : public clang::DynamicRecursiveASTVisitor {32public:33  explicit EvaluateConstantInitializersVisitor(VarInfoMap &VarInfo)34      : VarInfo(VarInfo) {}35 36  /// \brief Checks that isConstantInitializer and EvaluateAsRValue agree37  /// and don't crash.38  ///39  /// For each VarDecl with an initializer this also records in VarInfo40  /// whether the initializer could be evaluated as a constant.41  bool VisitVarDecl(clang::VarDecl *VD) override {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*/));48    }49    return true;50  }51 52 private:53  VarInfoMap &VarInfo;54};55 56class 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>();62  }63 64 private:65  class Consumer : public clang::ASTConsumer {66   public:67    ~Consumer() override {}68 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());77    }78  };79};80}81 82TEST(EvaluateAsRValue, FailsGracefullyForUnknownTypes) {83  // This is a regression test; the AST library used to trigger assertion84  // failures because it assumed that the type of initializers was always85  // 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));108  }109}110 111class CheckLValueToRValueConversionVisitor112    : public clang::DynamicRecursiveASTVisitor {113public:114  bool VisitDeclRefExpr(clang::DeclRefExpr *E) override {115    clang::Expr::EvalResult Result;116    E->EvaluateAsRValue(Result, E->getDecl()->getASTContext(), true);117 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());122 123    return true;124  }125};126 127class CheckConversionAction : public clang::ASTFrontendAction {128public:129  std::unique_ptr<clang::ASTConsumer>130  CreateASTConsumer(clang::CompilerInstance &Compiler,131                    llvm::StringRef FilePath) override {132    return std::make_unique<Consumer>();133  }134 135private:136  class Consumer : public clang::ASTConsumer {137  public:138    ~Consumer() override {}139 140    void HandleTranslationUnit(clang::ASTContext &Ctx) override {141      CheckLValueToRValueConversionVisitor Evaluator;142      Evaluator.TraverseDecl(Ctx.getTranslationUnitDecl());143    }144  };145};146 147TEST(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));155  }156}157