Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -867,6 +867,46 @@ } }; +//===----------------------------------------------------------------------===// +// Wrapper Expressions. +//===----------------------------------------------------------------------===// + +/// ConstantExpr - An expression that occurs in a constant context. +class ConstantExpr : public Expr { + Stmt *Val; +public: + ConstantExpr(Expr *val) + : Expr(ConstantExprClass, val->getType(), + val->getValueKind(), val->getObjectKind(), + val->isTypeDependent(), val->isValueDependent(), + val->isInstantiationDependent(), + val->containsUnexpandedParameterPack()), + Val(val) {} + + /// Build an empty constant expression wrapper. + explicit ConstantExpr(EmptyShell Empty) + : Expr(ConstantExprClass, Empty) {} + + const Expr *getSubExpr() const { return cast(Val); } + Expr *getSubExpr() { return cast(Val); } + void setSubExpr(Expr *E) { Val = E; } + + SourceLocation getBeginLoc() const LLVM_READONLY { + return Val->getBeginLoc(); + } + SourceLocation getEndLoc() const LLVM_READONLY { + return Val->getEndLoc(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ConstantExprClass; + } + + // Iterators + child_range children() { return Val->children(); } + const_child_range children() const { return Val->children(); } +}; + //===----------------------------------------------------------------------===// // Primary Expressions. //===----------------------------------------------------------------------===// Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -2199,6 +2199,10 @@ DEF_TRAVERSE_STMT(SwitchStmt, {}) DEF_TRAVERSE_STMT(WhileStmt, {}) +DEF_TRAVERSE_STMT(ConstantExpr, { + TRY_TO(TraverseStmt(S->getSubExpr())); +}) + DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, { TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo())); Index: include/clang/AST/StmtDataCollectors.td =================================================================== --- include/clang/AST/StmtDataCollectors.td +++ include/clang/AST/StmtDataCollectors.td @@ -14,6 +14,13 @@ }]; } +//--- Wrappers -----------------------------------------------------------// +class ConstantExpr { + code Code = [{ + addData(S->getType()); + }]; +} + //--- Builtin functionality ----------------------------------------------// class ArrayTypeTraitExpr { code Code = [{ Index: include/clang/Basic/StmtNodes.td =================================================================== --- include/clang/Basic/StmtNodes.td +++ include/clang/Basic/StmtNodes.td @@ -93,6 +93,9 @@ def GenericSelectionExpr : DStmt; def PseudoObjectExpr : DStmt; +// Wrapper expressions +def ConstantExpr : DStmt; + // Atomic expressions def AtomicExpr : DStmt; Index: include/clang/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -1616,6 +1616,9 @@ /// A MS-style AsmStmt record. STMT_MSASM, + /// A constant expression context. + EXPR_CONSTANT, + /// A PredefinedExpr record. EXPR_PREDEFINED, Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -3096,6 +3096,10 @@ // These never have a side-effect. return false; + case ConstantExprClass: + return cast(this)->getSubExpr()->HasSideEffects( + Ctx, IncludePossibleEffects); + case CallExprClass: case CXXOperatorCallExprClass: case CXXMemberCallExprClass: Index: lib/AST/ExprClassification.cpp =================================================================== --- lib/AST/ExprClassification.cpp +++ lib/AST/ExprClassification.cpp @@ -194,6 +194,9 @@ case Expr::DesignatedInitUpdateExprClass: return Cl::CL_PRValue; + case Expr::ConstantExprClass: + return ClassifyInternal(Ctx, cast(E)->getSubExpr()); + // Next come the complicated cases. case Expr::SubstNonTypeTemplateParmExprClass: return ClassifyInternal(Ctx, Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -11038,6 +11038,9 @@ return CheckICE(cast(E)->getReplacement(), Ctx); + case Expr::ConstantExprClass: + return CheckICE(cast(E)->getSubExpr(), Ctx); + case Expr::ParenExprClass: return CheckICE(cast(E)->getSubExpr(), Ctx); case Expr::GenericSelectionExprClass: Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -3524,6 +3524,10 @@ case Expr::CXXInheritedCtorInitExprClass: llvm_unreachable("unexpected statement kind"); + case Expr::ConstantExprClass: + E = cast(E)->getSubExpr(); + goto recurse; + // FIXME: invent manglings for all these. case Expr::BlockExprClass: case Expr::ChooseExprClass: Index: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp +++ lib/AST/StmtPrinter.cpp @@ -906,6 +906,10 @@ // Expr printing methods. //===----------------------------------------------------------------------===// +void StmtPrinter::VisitConstantExpr(ConstantExpr *Node) { + VisitExpr(Node->getSubExpr()); +} + void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { if (const auto *OCED = dyn_cast(Node->getDecl())) { OCED->getInit()->IgnoreImpCasts()->printPretty(OS, nullptr, Policy); Index: lib/AST/StmtProfile.cpp =================================================================== --- lib/AST/StmtProfile.cpp +++ lib/AST/StmtProfile.cpp @@ -996,6 +996,11 @@ VisitStmt(S); } +void StmtProfiler::VisitConstantExpr(const ConstantExpr *S) { + VisitExpr(S); + VisitExpr(S->getSubExpr()); +} + void StmtProfiler::VisitDeclRefExpr(const DeclRefExpr *S) { VisitExpr(S); if (!Canonical) Index: lib/Sema/SemaExceptionSpec.cpp =================================================================== --- lib/Sema/SemaExceptionSpec.cpp +++ lib/Sema/SemaExceptionSpec.cpp @@ -1051,6 +1051,9 @@ // [Can throw] if in a potentially-evaluated context the expression would // contain: switch (E->getStmtClass()) { + case Expr::ConstantExprClass: + return canThrow(cast(E)->getSubExpr()); + case Expr::CXXThrowExprClass: // - a potentially evaluated throw-expression return CT_Can; Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -8914,6 +8914,12 @@ //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// +template +ExprResult +TreeTransform::TransformConstantExpr(ConstantExpr *E) { + return TransformExpr(E->getSubExpr()); +} + template ExprResult TreeTransform::TransformPredefinedExpr(PredefinedExpr *E) { Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -491,6 +491,11 @@ "Incorrect expression field count"); } +void ASTStmtReader::VisitConstantExpr(ConstantExpr *E) { + VisitExpr(E); + E->setSubExpr(Record.readSubExpr()); +} + void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) { VisitExpr(E); E->setLocation(ReadSourceLocation()); @@ -2335,6 +2340,10 @@ Record[ASTStmtReader::NumStmtFields]); break; + case EXPR_CONSTANT: + S = new (Context) ConstantExpr(Empty); + break; + case EXPR_PREDEFINED: S = new (Context) PredefinedExpr(Empty); break; Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -386,6 +386,12 @@ Record.push_back(E->getObjectKind()); } +void ASTStmtWriter::VisitConstantExpr(ConstantExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getSubExpr()); + Code = serialization::EXPR_CONSTANT; +} + void ASTStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) { VisitExpr(E); Record.AddSourceLocation(E->getLocation()); Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1267,6 +1267,9 @@ case Stmt::ObjCPropertyRefExprClass: llvm_unreachable("These are handled by PseudoObjectExpr"); + case Expr::ConstantExprClass: + return Visit(cast(S)->getSubExpr(), Pred, DstTop); + case Stmt::GNUNullExprClass: { // GNU __null is a pointer-width integer, not an actual pointer. ProgramStateRef state = Pred->getState(); Index: tools/libclang/CXCursor.cpp =================================================================== --- tools/libclang/CXCursor.cpp +++ tools/libclang/CXCursor.cpp @@ -343,6 +343,10 @@ K = CXCursor_CharacterLiteral; break; + case Stmt::ConstantExprClass: + return MakeCXCursor(cast(S)->getSubExpr(), + Parent, TU, RegionOfInterest); + case Stmt::ParenExprClass: K = CXCursor_ParenExpr; break;