123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- //===- unittests/AST/EvaluateAsRValueTest.cpp -----------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // \file
- // \brief Unit tests for evaluation of constant initializers.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/AST/ASTConsumer.h"
- #include "clang/AST/ASTConsumer.h"
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/RecursiveASTVisitor.h"
- #include "clang/Tooling/Tooling.h"
- #include "gtest/gtest.h"
- #include <map>
- #include <string>
- using namespace clang::tooling;
- namespace {
- // For each variable name encountered, whether its initializer was a
- // constant.
- typedef std::map<std::string, bool> VarInfoMap;
- /// \brief Records information on variable initializers to a map.
- class EvaluateConstantInitializersVisitor
- : public clang::RecursiveASTVisitor<EvaluateConstantInitializersVisitor> {
- public:
- explicit EvaluateConstantInitializersVisitor(VarInfoMap &VarInfo)
- : VarInfo(VarInfo) {}
- /// \brief Checks that isConstantInitializer and EvaluateAsRValue agree
- /// and don't crash.
- ///
- /// For each VarDecl with an initializer this also records in VarInfo
- /// whether the initializer could be evaluated as a constant.
- bool VisitVarDecl(const clang::VarDecl *VD) {
- if (const clang::Expr *Init = VD->getInit()) {
- clang::Expr::EvalResult Result;
- bool WasEvaluated = Init->EvaluateAsRValue(Result, VD->getASTContext());
- VarInfo[VD->getNameAsString()] = WasEvaluated;
- EXPECT_EQ(WasEvaluated, Init->isConstantInitializer(VD->getASTContext(),
- false /*ForRef*/));
- }
- return true;
- }
- private:
- VarInfoMap &VarInfo;
- };
- class EvaluateConstantInitializersAction : public clang::ASTFrontendAction {
- public:
- std::unique_ptr<clang::ASTConsumer>
- CreateASTConsumer(clang::CompilerInstance &Compiler,
- llvm::StringRef FilePath) override {
- return std::make_unique<Consumer>();
- }
- private:
- class Consumer : public clang::ASTConsumer {
- public:
- ~Consumer() override {}
- void HandleTranslationUnit(clang::ASTContext &Ctx) override {
- VarInfoMap VarInfo;
- EvaluateConstantInitializersVisitor Evaluator(VarInfo);
- Evaluator.TraverseDecl(Ctx.getTranslationUnitDecl());
- EXPECT_EQ(2u, VarInfo.size());
- EXPECT_FALSE(VarInfo["Dependent"]);
- EXPECT_TRUE(VarInfo["Constant"]);
- EXPECT_EQ(2u, VarInfo.size());
- }
- };
- };
- }
- TEST(EvaluateAsRValue, FailsGracefullyForUnknownTypes) {
- // This is a regression test; the AST library used to trigger assertion
- // failures because it assumed that the type of initializers was always
- // known (which is true only after template instantiation).
- std::string ModesToTest[] = {"-std=c++03", "-std=c++11", "-std=c++1y"};
- for (std::string const &Mode : ModesToTest) {
- std::vector<std::string> Args(1, Mode);
- Args.push_back("-fno-delayed-template-parsing");
- ASSERT_TRUE(runToolOnCodeWithArgs(
- std::make_unique<EvaluateConstantInitializersAction>(),
- "template <typename T>"
- "struct vector {"
- " explicit vector(int size);"
- "};"
- "template <typename R>"
- "struct S {"
- " vector<R> intervals() const {"
- " vector<R> Dependent(2);"
- " return Dependent;"
- " }"
- "};"
- "void doSomething() {"
- " int Constant = 2 + 2;"
- " (void) Constant;"
- "}",
- Args));
- }
- }
|