diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -567,11 +567,14 @@ // polymorphic class type [...] [the] expression is an unevaluated // operand. [...] if (RecordD->isPolymorphic() && E->isGLValue()) { - // The subexpression is potentially evaluated; switch the context - // and recheck the subexpression. - ExprResult Result = TransformToPotentiallyEvaluated(E); - if (Result.isInvalid()) return ExprError(); - E = Result.get(); + if (isUnevaluatedContext()) { + // The operand was processed in unevaluated context, switch the + // context and recheck the subexpression. + ExprResult Result = TransformToPotentiallyEvaluated(E); + if (Result.isInvalid()) + return ExprError(); + E = Result.get(); + } // We require a vtable to query the type at run time. MarkVTableUsed(TypeidLoc, RecordD); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -11592,15 +11592,20 @@ TInfo, E->getEndLoc()); } - // We don't know whether the subexpression is potentially evaluated until - // after we perform semantic analysis. We speculatively assume it is - // unevaluated; it will get fixed later if the subexpression is in fact - // potentially evaluated. - EnterExpressionEvaluationContext Unevaluated( - SemaRef, Sema::ExpressionEvaluationContext::Unevaluated, - Sema::ReuseLambdaContextDecl); - - ExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand()); + // Typeid's operand is an unevaluated context, unless it's a polymorphic + // type. We must not unilaterally enter unevaluated context here, as then + // semantic processing can re-transform an already transformed operand. + Expr *Op = E->getExprOperand(); + auto EvalCtx = Sema::ExpressionEvaluationContext::Unevaluated; + if (E->isGLValue()) + if (auto *RecordT = Op->getType()->getAs()) + if (cast(RecordT->getDecl())->isPolymorphic()) + EvalCtx = SemaRef.ExprEvalContexts.back().Context; + + EnterExpressionEvaluationContext Unevaluated(SemaRef, EvalCtx, + Sema::ReuseLambdaContextDecl); + + ExprResult SubExpr = getDerived().TransformExpr(Op); if (SubExpr.isInvalid()) return ExprError(); diff --git a/clang/test/SemaCXX/pr50497-crash-typeid.cpp b/clang/test/SemaCXX/pr50497-crash-typeid.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/pr50497-crash-typeid.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -verify %s -Wno-unevaluated-expression +// Don't crash (PR50497). + +// expected-no-diagnostics +namespace std { +class type_info; +} + +class Ex { + // polymorphic + virtual ~Ex(); +}; +void Frob(const std::type_info &type); + +void Foo(Ex *ex) { + // generic lambda + [=](auto rate) { + // typeid + Frob(typeid(*ex)); + }(1); + + [=](auto rate) { + // unevaluated nested typeid + Frob(typeid((typeid(*ex), ex))); + }(1); +}