Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -653,12 +653,18 @@ } template bool ByteCodeExprGen::discard(const Expr *E) { + if (E->containsErrors()) + return false; + OptionScope Scope(this, /*NewDiscardResult=*/true); return this->Visit(E); } template bool ByteCodeExprGen::visit(const Expr *E) { + if (E->containsErrors()) + return false; + OptionScope Scope(this, /*NewDiscardResult=*/false); return this->Visit(E); } @@ -1226,8 +1232,10 @@ /// We need to evaluate the initializer and return its value. template bool ByteCodeExprGen::visitDecl(const VarDecl *VD) { - Optional VarT = classify(VD->getType()); + if (VD->isInvalidDecl()) + return false; + Optional VarT = classify(VD->getType()); // Create and initialize the variable. if (!this->visitVarDecl(VD)) return false; Index: clang/test/AST/Interp/functions.cpp =================================================================== --- clang/test/AST/Interp/functions.cpp +++ clang/test/AST/Interp/functions.cpp @@ -84,3 +84,18 @@ return 5; } static_assert(a() == 5, ""); + +constexpr int invalid() { + // Invalid expression in visit(). + while(huh) {} // expected-error {{use of undeclared identifier}} \ + // ref-error {{use of undeclared identifier}} + + return 0; +} + +constexpr void invalid2() { + int i = 0; + // Invalid expression in discard(). + huh(); // expected-error {{use of undeclared identifier}} \ + // ref-error {{use of undeclared identifier}} +}