EvaluateAsRValueTest.cpp 3.7 KB

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