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 /lib/AST | |
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
Diffstat (limited to 'lib/AST')
-rw-r--r-- | lib/AST/DeclBase.cpp | 6 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 82 | ||||
-rw-r--r-- | lib/AST/ExprClassification.cpp | 5 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 1 | ||||
-rw-r--r-- | lib/AST/ItaniumMangle.cpp | 1 | ||||
-rw-r--r-- | lib/AST/StmtDumper.cpp | 10 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 4 | ||||
-rw-r--r-- | lib/AST/StmtProfile.cpp | 9 |
8 files changed, 117 insertions, 1 deletions
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 @@ -1027,6 +1027,10 @@ void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) { OS << ")"; } +void StmtPrinter::VisitPseudoObjectExpr(PseudoObjectExpr *Node) { + PrintExpr(Node->getSyntacticForm()); +} + void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) { const char *Name = 0; switch (Node->getOp()) { diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index db97e59804..5a6b771b9a 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -475,6 +475,15 @@ void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) { } } +void StmtProfiler::VisitPseudoObjectExpr(const PseudoObjectExpr *S) { + VisitExpr(S); + for (PseudoObjectExpr::const_semantics_iterator + i = S->semantics_begin(), e = S->semantics_end(); i != e; ++i) + // Normally, we would not profile the source expressions of OVEs. + if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(*i)) + Visit(OVE->getSourceExpr()); +} + void StmtProfiler::VisitAtomicExpr(const AtomicExpr *S) { VisitExpr(S); ID.AddInteger(S->getOp()); |