diff options
author | John McCall <rjmccall@apple.com> | 2011-11-06 09:01:30 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-11-06 09:01:30 +0000 |
commit | 4b9c2d235fb9449e249d74f48ecfec601650de93 (patch) | |
tree | 6e4dcbc7c1cf85896e1be0ee0f29211b0d998393 | |
parent | a463089f6eb37069d406f9fb56e40810edaf523a (diff) |
Change the AST representation of operations on Objective-C
property references to use a new PseudoObjectExpr
expression which pairs a syntactic form of the expression
with a set of semantic expressions implementing it.
This should significantly reduce the complexity required
elsewhere in the compiler to deal with these kinds of
expressions (e.g. IR generation's special l-value kind,
the static analyzer's Message abstraction), at the lower
cost of specifically dealing with the odd AST structure
of these expressions. It should also greatly simplify
efforts to implement similar language features in the
future, most notably Managed C++'s properties and indexed
properties.
Most of the effort here is in dealing with the various
clients of the AST. I've gone ahead and simplified the
ObjC rewriter's use of properties; other clients, like
IR-gen and the static analyzer, have all the old
complexity *and* all the new complexity, at least
temporarily. Many thanks to Ted for writing and advising
on the necessary changes to the static analyzer.
I've xfailed a small diagnostics regression in the static
analyzer at Ted's request.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143867 91177308-0d34-0410-b5e6-96231b3b80d8
40 files changed, 1674 insertions, 652 deletions
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 37a9f072af..5d95cc81c7 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -974,6 +974,14 @@ public: /// declaration context DC. bool Encloses(const DeclContext *DC) const; + /// \brief Find the nearest non-closure ancestor of this context, + /// i.e. the innermost semantic parent of this context which is not + /// a closure. A context may be its own non-closure ancestor. + DeclContext *getNonClosureAncestor(); + const DeclContext *getNonClosureAncestor() const { + return const_cast<DeclContext*>(this)->getNonClosureAncestor(); + } + /// getPrimaryContext - There may be many different /// declarations of the same entity (including forward declarations /// of classes, multiple definitions of namespaces, etc.), each with diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index fd88e1e88e..3ea590cd84 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -2758,6 +2758,13 @@ public: bool isCompoundAssignmentOp() const { return isCompoundAssignmentOp(getOpcode()); } + static Opcode getOpForCompoundAssignment(Opcode Opc) { + assert(isCompoundAssignmentOp(Opc)); + if (Opc >= BO_XorAssign) + return Opcode(unsigned(Opc) - BO_XorAssign + BO_Xor); + else + return Opcode(unsigned(Opc) - BO_MulAssign + BO_Mul); + } static bool isShiftAssignOp(Opcode Opc) { return Opc == BO_ShlAssign || Opc == BO_ShrAssign; @@ -4251,6 +4258,140 @@ public: child_range children() { return child_range(&SrcExpr, &SrcExpr+1); } }; +/// PseudoObjectExpr - An expression which accesses a pseudo-object +/// l-value. A pseudo-object is an abstract object, accesses to which +/// are translated to calls. The pseudo-object expression has a +/// syntactic form, which shows how the expression was actually +/// written in the source code, and a semantic form, which is a series +/// of expressions to be executed in order which detail how the +/// operation is actually evaluated. Optionally, one of the semantic +/// forms may also provide a result value for the expression. +/// +/// If any of the semantic-form expressions is an OpaqueValueExpr, +/// that OVE is required to have a source expression, and it is bound +/// to the result of that source expression. Such OVEs may appear +/// only in subsequent semantic-form expressions and as +/// sub-expressions of the syntactic form. +/// +/// PseudoObjectExpr should be used only when an operation can be +/// usefully described in terms of fairly simple rewrite rules on +/// objects and functions that are meant to be used by end-developers. +/// For example, under the Itanium ABI, dynamic casts are implemented +/// as a call to a runtime function called __dynamic_cast; using this +/// class to describe that would be inappropriate because that call is +/// not really part of the user-visible semantics, and instead the +/// cast is properly reflected in the AST and IR-generation has been +/// taught to generate the call as necessary. In contrast, an +/// Objective-C property access is semantically defined to be +/// equivalent to a particular message send, and this is very much +/// part of the user model. The name of this class encourages this +/// modelling design. +class PseudoObjectExpr : public Expr { + // PseudoObjectExprBits.NumSubExprs - The number of sub-expressions. + // Always at least two, because the first sub-expression is the + // syntactic form. + + // PseudoObjectExprBits.ResultIndex - The index of the + // sub-expression holding the result. 0 means the result is void, + // which is unambiguous because it's the index of the syntactic + // form. Note that this is therefore 1 higher than the value passed + // in to Create, which is an index within the semantic forms. + // Note also that ASTStmtWriter assumes this encoding. + + Expr **getSubExprsBuffer() { return reinterpret_cast<Expr**>(this + 1); } + const Expr * const *getSubExprsBuffer() const { + return reinterpret_cast<const Expr * const *>(this + 1); + } + + friend class ASTStmtReader; + + PseudoObjectExpr(QualType type, ExprValueKind VK, + Expr *syntactic, ArrayRef<Expr*> semantic, + unsigned resultIndex); + + PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs); + + unsigned getNumSubExprs() const { + return PseudoObjectExprBits.NumSubExprs; + } + +public: + /// NoResult - A value for the result index indicating that there is + /// no semantic result. + enum { NoResult = ~0U }; + + static PseudoObjectExpr *Create(ASTContext &Context, Expr *syntactic, + ArrayRef<Expr*> semantic, + unsigned resultIndex); + + static PseudoObjectExpr *Create(ASTContext &Context, EmptyShell shell, + unsigned numSemanticExprs); + + /// Return the syntactic form of this expression, i.e. the + /// expression it actually looks like. Likely to be expressed in + /// terms of OpaqueValueExprs bound in the semantic form. + Expr *getSyntacticForm() { return getSubExprsBuffer()[0]; } + const Expr *getSyntacticForm() const { return getSubExprsBuffer()[0]; } + + /// Return the index of the result-bearing expression into the semantics + /// expressions, or PseudoObjectExpr::NoResult if there is none. + unsigned getResultExprIndex() const { + if (PseudoObjectExprBits.ResultIndex == 0) return NoResult; + return PseudoObjectExprBits.ResultIndex - 1; + } + + /// Return the result-bearing expression, or null if there is none. + Expr *getResultExpr() { + if (PseudoObjectExprBits.ResultIndex == 0) + return 0; + return getSubExprsBuffer()[PseudoObjectExprBits.ResultIndex]; + } + const Expr *getResultExpr() const { + return const_cast<PseudoObjectExpr*>(this)->getResultExpr(); + } + + unsigned getNumSemanticExprs() const { return getNumSubExprs() - 1; } + + typedef Expr * const *semantics_iterator; + typedef const Expr * const *const_semantics_iterator; + semantics_iterator semantics_begin() { + return getSubExprsBuffer() + 1; + } + const_semantics_iterator semantics_begin() const { + return getSubExprsBuffer() + 1; + } + semantics_iterator semantics_end() { + return getSubExprsBuffer() + getNumSubExprs(); + } + const_semantics_iterator semantics_end() const { + return getSubExprsBuffer() + getNumSubExprs(); + } + Expr *getSemanticExpr(unsigned index) { + assert(index + 1 < getNumSubExprs()); + return getSubExprsBuffer()[index + 1]; + } + const Expr *getSemanticExpr(unsigned index) const { + return const_cast<PseudoObjectExpr*>(this)->getSemanticExpr(index); + } + + SourceLocation getExprLoc() const { + return getSyntacticForm()->getExprLoc(); + } + SourceRange getSourceRange() const { + return getSyntacticForm()->getSourceRange(); + } + + child_range children() { + Stmt **cs = reinterpret_cast<Stmt**>(getSubExprsBuffer()); + return child_range(cs, cs + getNumSubExprs()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == PseudoObjectExprClass; + } + static bool classof(const PseudoObjectExpr *) { return true; } +}; + /// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*, /// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the /// similarly-named C++0x instructions. All of these instructions take one diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 9b65063d35..409f83019f 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1874,6 +1874,23 @@ TraverseGenericSelectionExpr(GenericSelectionExpr *S) { return true; } +// PseudoObjectExpr is a special case because of the wierdness with +// syntactic expressions and opaque values. +template<typename Derived> +bool RecursiveASTVisitor<Derived>:: +TraversePseudoObjectExpr(PseudoObjectExpr *S) { + TRY_TO(WalkUpFromPseudoObjectExpr(S)); + TRY_TO(TraverseStmt(S->getSyntacticForm())); + for (PseudoObjectExpr::semantics_iterator + i = S->semantics_begin(), e = S->semantics_end(); i != e; ++i) { + Expr *sub = *i; + if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(sub)) + sub = OVE->getSourceExpr(); + TRY_TO(TraverseStmt(sub)); + } + return true; +} + DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, { // This is called for code like 'return T()' where T is a built-in // (i.e. non-class) type. diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 8840719413..83836b717b 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -146,6 +146,7 @@ protected: friend class CXXUnresolvedConstructExpr; // ctor friend class CXXDependentScopeMemberExpr; // ctor friend class OverloadExpr; // ctor + friend class PseudoObjectExpr; // ctor friend class AtomicExpr; // ctor unsigned : NumStmtBits; @@ -184,6 +185,18 @@ protected: unsigned NumPreArgs : 1; }; + class PseudoObjectExprBitfields { + friend class PseudoObjectExpr; + friend class ASTStmtReader; // deserialization + + unsigned : NumExprBits; + + // These don't need to be particularly wide, because they're + // strictly limited by the forms of expressions we permit. + unsigned NumSubExprs : 8; + unsigned ResultIndex : 32 - 8 - NumExprBits; + }; + class ObjCIndirectCopyRestoreExprBitfields { friend class ObjCIndirectCopyRestoreExpr; unsigned : NumExprBits; @@ -201,6 +214,7 @@ protected: DeclRefExprBitfields DeclRefExprBits; CastExprBitfields CastExprBits; CallExprBitfields CallExprBits; + PseudoObjectExprBitfields PseudoObjectExprBits; ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits; }; diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index 02aec8cfef..6bb38d0ce7 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -77,6 +77,7 @@ def ImplicitValueInitExpr : DStmt<Expr>; def ParenListExpr : DStmt<Expr>; def VAArgExpr : DStmt<Expr>; def GenericSelectionExpr : DStmt<Expr>; +def PseudoObjectExpr : DStmt<Expr>; // Atomic expressions def AtomicExpr : DStmt<Expr>; diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 982c31d293..fc97d29046 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -1000,6 +1000,8 @@ namespace clang { EXPR_BLOCK_DECL_REF, /// \brief A GenericSelectionExpr record. EXPR_GENERIC_SELECTION, + /// \brief A PseudoObjectExpr record. + EXPR_PSEUDO_OBJECT, /// \brief An AtomicExpr record. EXPR_ATOMIC, diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp index bf2517f119..6eb82093cf 100644 --- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp +++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp @@ -160,12 +160,14 @@ private: if (!E) return false; E = E->IgnoreParenCasts(); + + // Also look through property-getter sugar. + if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E)) + E = pseudoOp->getResultExpr()->IgnoreImplicit(); + if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel); - if (ObjCPropertyRefExpr *propE = dyn_cast<ObjCPropertyRefExpr>(E)) - return propE->getGetterSelector() == DelegateSel; - return false; } diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp index 69fb2e8949..3bfa15c6e0 100644 --- a/lib/ARCMigrate/TransUnbridgedCasts.cpp +++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp @@ -236,7 +236,15 @@ private: } } - if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getSubExpr())){ + Expr *subExpr = E->getSubExpr(); + + // Look through pseudo-object expressions. + if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) { + subExpr = pseudo->getResultExpr(); + assert(subExpr && "no result for pseudo-object of non-void type?"); + } + + if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) { if (implCE->getCastKind() == CK_ARCConsumeObject) return rewriteToBridgedCast(E, OBC_BridgeRetained); if (implCE->getCastKind() == CK_ARCReclaimReturnedObject) diff --git a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp index 7c533bcf3a..d1f08aac28 100644 --- a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp +++ b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp @@ -78,6 +78,15 @@ public: return true; } + bool VisitPseudoObjectExpr(PseudoObjectExpr *POE) { + if (isZeroingPropIvar(POE) && isRemovable(POE)) { + Transaction Trans(Pass.TA); + Pass.TA.removeStmt(POE); + } + + return true; + } + bool VisitBinaryOperator(BinaryOperator *BOE) { if (isZeroingPropIvar(BOE) && isRemovable(BOE)) { Transaction Trans(Pass.TA); @@ -142,17 +151,21 @@ private: } bool isZeroingPropIvar(Expr *E) { - BinaryOperator *BOE = dyn_cast_or_null<BinaryOperator>(E); - if (!BOE) return false; + E = E->IgnoreParens(); + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) + return isZeroingPropIvar(BO); + if (PseudoObjectExpr *PO = dyn_cast<PseudoObjectExpr>(E)) + return isZeroingPropIvar(PO); + return false; + } + bool isZeroingPropIvar(BinaryOperator *BOE) { if (BOE->getOpcode() == BO_Comma) return isZeroingPropIvar(BOE->getLHS()) && isZeroingPropIvar(BOE->getRHS()); if (BOE->getOpcode() != BO_Assign) - return false; - - ASTContext &Ctx = Pass.Ctx; + return false; Expr *LHS = BOE->getLHS(); if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) { @@ -172,25 +185,38 @@ private: if (!IvarBacksPropertySynthesis) return false; } - else if (ObjCPropertyRefExpr *PropRefExp = dyn_cast<ObjCPropertyRefExpr>(LHS)) { - // TODO: Using implicit property decl. - if (PropRefExp->isImplicitProperty()) - return false; - if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) { - if (!SynthesizedProperties.count(PDecl)) - return false; - } - } else return false; - Expr *RHS = BOE->getRHS(); - bool RHSIsNull = RHS->isNullPointerConstant(Ctx, - Expr::NPC_ValueDependentIsNull); - if (RHSIsNull) + return isZero(BOE->getRHS()); + } + + bool isZeroingPropIvar(PseudoObjectExpr *PO) { + BinaryOperator *BO = dyn_cast<BinaryOperator>(PO->getSyntacticForm()); + if (!BO) return false; + if (BO->getOpcode() != BO_Assign) return false; + + ObjCPropertyRefExpr *PropRefExp = + dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParens()); + if (!PropRefExp) return false; + + // TODO: Using implicit property decl. + if (PropRefExp->isImplicitProperty()) + return false; + + if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) { + if (!SynthesizedProperties.count(PDecl)) + return false; + } + + return isZero(cast<OpaqueValueExpr>(BO->getRHS())->getSourceExpr()); + } + + bool isZero(Expr *E) { + if (E->isNullPointerConstant(Pass.Ctx, Expr::NPC_ValueDependentIsNull)) return true; - return isZeroingPropIvar(RHS); + return isZeroingPropIvar(E); } }; diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index a4daea2287..4c31bbd3d7 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -640,7 +640,11 @@ void Decl::CheckAccessDeclContext() const { } DeclContext *Decl::getNonClosureContext() { - DeclContext *DC = getDeclContext(); + return getDeclContext()->getNonClosureAncestor(); +} + +DeclContext *DeclContext::getNonClosureAncestor() { + DeclContext *DC = this; // This is basically "while (DC->isClosure()) DC = DC->getParent();" // except that it's significantly more efficient to cast to a known diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 3239973688..6eb6116b01 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1694,6 +1694,19 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, R1 = getSourceRange(); return true; + case PseudoObjectExprClass: { + const PseudoObjectExpr *PO = cast<PseudoObjectExpr>(this); + + // Only complain about things that have the form of a getter. + if (isa<UnaryOperator>(PO->getSyntacticForm()) || + isa<BinaryOperator>(PO->getSyntacticForm())) + return false; + + Loc = getExprLoc(); + R1 = getSourceRange(); + return true; + } + case StmtExprClass: { // Statement exprs don't logically have side effects themselves, but are // sometimes used in macros in ways that give them a type that is unused. @@ -2598,6 +2611,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx, } else if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(this)) { return M->GetTemporaryExpr()->isNullPointerConstant(Ctx, NPC); + } else if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(this)) { + if (const Expr *Source = OVE->getSourceExpr()) + return Source->isNullPointerConstant(Ctx, NPC); } // C++0x nullptr_t is always a null pointer constant. @@ -3306,6 +3322,72 @@ const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) { return cast<OpaqueValueExpr>(e); } +PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &Context, EmptyShell sh, + unsigned numSemanticExprs) { + void *buffer = Context.Allocate(sizeof(PseudoObjectExpr) + + (1 + numSemanticExprs) * sizeof(Expr*), + llvm::alignOf<PseudoObjectExpr>()); + return new(buffer) PseudoObjectExpr(sh, numSemanticExprs); +} + +PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs) + : Expr(PseudoObjectExprClass, shell) { + PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1; +} + +PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &C, Expr *syntax, + ArrayRef<Expr*> semantics, + unsigned resultIndex) { + assert(syntax && "no syntactic expression!"); + assert(semantics.size() && "no semantic expressions!"); + + QualType type; + ExprValueKind VK; + if (resultIndex == NoResult) { + type = C.VoidTy; + VK = VK_RValue; + } else { + assert(resultIndex < semantics.size()); + type = semantics[resultIndex]->getType(); + VK = semantics[resultIndex]->getValueKind(); + assert(semantics[resultIndex]->getObjectKind() == OK_Ordinary); + } + + void *buffer = C.Allocate(sizeof(PseudoObjectExpr) + + (1 + semantics.size()) * sizeof(Expr*), + llvm::alignOf<PseudoObjectExpr>()); + return new(buffer) PseudoObjectExpr(type, VK, syntax, semantics, + resultIndex); +} + +PseudoObjectExpr::PseudoObjectExpr(QualType type, ExprValueKind VK, + Expr *syntax, ArrayRef<Expr*> semantics, + unsigned resultIndex) + : Expr(PseudoObjectExprClass, type, VK, OK_Ordinary, + /*filled in at end of ctor*/ false, false, false, false) { + PseudoObjectExprBits.NumSubExprs = semantics.size() + 1; + PseudoObjectExprBits.ResultIndex = resultIndex + 1; + + for (unsigned i = 0, e = semantics.size() + 1; i != e; ++i) { + Expr *E = (i == 0 ? syntax : semantics[i-1]); + getSubExprsBuffer()[i] = E; + + if (E->isTypeDependent()) + ExprBits.TypeDependent = true; + if (E->isValueDependent()) + ExprBits.ValueDependent = true; + if (E->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; + if (E->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + if (isa<OpaqueValueExpr>(E)) + assert(cast<OpaqueValueExpr>(E)->getSourceExpr() != 0 && + "opaque-value semantic expressions for pseudo-object " + "operations must have sources"); + } +} + //===----------------------------------------------------------------------===// // ExprIterator. //===----------------------------------------------------------------------===// diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index 594ae69ec4..1251b96fba 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -232,6 +232,11 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { return ClassifyExprValueKind(Lang, E, cast<OpaqueValueExpr>(E)->getValueKind()); + // Pseudo-object expressions can produce l-values with reference magic. + case Expr::PseudoObjectExprClass: + return ClassifyExprValueKind(Lang, E, + cast<PseudoObjectExpr>(E)->getValueKind()); + // Implicit casts are lvalues if they're lvalue casts. Other than that, we // only specifically record class temporaries. case Expr::ImplicitCastExprClass: diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 3011b7f25f..9c9e473f7b 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -3450,6 +3450,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::AsTypeExprClass: case Expr::ObjCIndirectCopyRestoreExprClass: case Expr::MaterializeTemporaryExprClass: + case Expr::PseudoObjectExprClass: case Expr::AtomicExprClass: return ICEDiag(2, E->getLocStart()); diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 889cf513bb..b2e1d20ca0 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -2257,6 +2257,7 @@ recurse: case Expr::CXXNoexceptExprClass: case Expr::CUDAKernelCallExprClass: case Expr::AsTypeExprClass: + case Expr::PseudoObjectExprClass: case Expr::AtomicExprClass: { // As bad as this diagnostic is, it's better than crashing. diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index 54e62fe35b..2248343199 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -148,6 +148,7 @@ namespace { void VisitCompoundAssignOperator(CompoundAssignOperator *Node); void VisitAddrLabelExpr(AddrLabelExpr *Node); void VisitBlockExpr(BlockExpr *Node); + void VisitOpaqueValueExpr(OpaqueValueExpr *Node); // C++ void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node); @@ -524,6 +525,15 @@ void StmtDumper::VisitBlockExpr(BlockExpr *Node) { DumpSubTree(block->getBody()); } +void StmtDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) { + DumpExpr(Node); + + if (Expr *Source = Node->getSourceExpr()) { + OS << '\n'; + DumpSubTree(Source); + } +} + // GNU extensions. void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) { diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 5b1654c924..04617bf9ac 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp |