diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -14934,25 +14934,27 @@ /// lvalue-to-rvalue cast if it is an lvalue. static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) { assert(!E->isValueDependent()); + + if (E->getType().isNull()) + return false; + + if (!CheckLiteralType(Info, E)) + return false; + if (Info.EnableNewConstInterp) { if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result)) return false; } else { - if (E->getType().isNull()) - return false; - - if (!CheckLiteralType(Info, E)) - return false; - if (!::Evaluate(Result, Info, E)) return false; + } - if (E->isGLValue()) { - LValue LV; - LV.setFrom(Info.Ctx, Result); - if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result)) - return false; - } + // Implicit lvalue-to-rvalue cast. + if (E->isGLValue()) { + LValue LV; + LV.setFrom(Info.Ctx, Result); + if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result)) + return false; } // Check this core constant expression is a constant expression. diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -11,6 +11,7 @@ static_assert(number == 10, ""); static_assert(number != 10, ""); // expected-error{{failed}} \ // ref-error{{failed}} \ + // expected-note{{evaluates to}} \ // ref-note{{evaluates to}} constexpr bool getTrue() { return true; } diff --git a/clang/unittests/AST/EvaluateAsRValueTest.cpp b/clang/unittests/AST/EvaluateAsRValueTest.cpp --- a/clang/unittests/AST/EvaluateAsRValueTest.cpp +++ b/clang/unittests/AST/EvaluateAsRValueTest.cpp @@ -107,3 +107,50 @@ Args)); } } + +class CheckLValueToRValueConversionVisitor + : public clang::RecursiveASTVisitor { +public: + bool VisitDeclRefExpr(const clang::DeclRefExpr *E) { + clang::Expr::EvalResult Result; + E->EvaluateAsRValue(Result, E->getDecl()->getASTContext(), true); + + EXPECT_TRUE(Result.Val.hasValue()); + // Since EvaluateAsRValue does an implicit lvalue-to-rvalue conversion, + // the result cannot be a LValue. + EXPECT_FALSE(Result.Val.isLValue()); + + return true; + } +}; + +class CheckConversionAction : public clang::ASTFrontendAction { +public: + std::unique_ptr + CreateASTConsumer(clang::CompilerInstance &Compiler, + llvm::StringRef FilePath) override { + return std::make_unique(); + } + +private: + class Consumer : public clang::ASTConsumer { + public: + ~Consumer() override {} + + void HandleTranslationUnit(clang::ASTContext &Ctx) override { + CheckLValueToRValueConversionVisitor Evaluator; + Evaluator.TraverseDecl(Ctx.getTranslationUnitDecl()); + } + }; +}; + +TEST(EvaluateAsRValue, LValueToRValueConversionWorks) { + std::string ModesToTest[] = {"", "-fexperimental-new-constant-interpreter"}; + for (std::string const &Mode : ModesToTest) { + std::vector Args(1, Mode); + ASSERT_TRUE(runToolOnCodeWithArgs(std::make_unique(), + "constexpr int a = 20;\n" + "static_assert(a == 20, \"\");\n", + Args)); + } +}