diff options
| author | John McCall <rjmccall@apple.com> | 2011-11-30 04:42:31 +0000 |
|---|---|---|
| committer | John McCall <rjmccall@apple.com> | 2011-11-30 04:42:31 +0000 |
| commit | e929082806fce5178755272bd5975d12f8a78065 (patch) | |
| tree | f1adc59b47f9708223ff4f12dfb44d5e3d9e18a7 | |
| parent | f7a700fd01deb5b8fc6835cba99c7251e7aafe8f (diff) | |
| download | bcm5719-llvm-e929082806fce5178755272bd5975d12f8a78065.tar.gz bcm5719-llvm-e929082806fce5178755272bd5975d12f8a78065.zip | |
Fix the instantiation of pseudo-object expressions. This is a
really bad way to go about this, but I'm not sure there's a better
choice without substantial changes to TreeTransform --- most
notably, preserving implicit semantic nodes instead of discarding
and rebuilding them.
llvm-svn: 145480
| -rw-r--r-- | clang/include/clang/Sema/Sema.h | 2 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaPseudoObject.cpp | 51 | ||||
| -rw-r--r-- | clang/lib/Sema/TreeTransform.h | 10 | ||||
| -rw-r--r-- | clang/test/CodeGenObjCXX/property-reference.mm | 42 |
4 files changed, 103 insertions, 2 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 66d0baf73b2..eccde04aff5 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -127,6 +127,7 @@ namespace clang { class ParmVarDecl; class Preprocessor; class PseudoDestructorTypeStorage; + class PseudoObjectExpr; class QualType; class StandardConversionSequence; class Stmt; @@ -5803,6 +5804,7 @@ public: BinaryOperatorKind Opcode, Expr *LHS, Expr *RHS); ExprResult checkPseudoObjectRValue(Expr *E); + Expr *recreateSyntacticForm(PseudoObjectExpr *E); QualType CheckConditionalOperands( // C99 6.5.15 ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index 3bd671d10cd..08b3fc82ca3 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -790,3 +790,54 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc, llvm_unreachable("unknown pseudo-object kind!"); } } + +/// Given a pseudo-object reference, rebuild it without the opaque +/// values. Basically, undo the behavior of rebuildAndCaptureObject. +/// This should never operate in-place. +static Expr *stripOpaqueValuesFromPseudoObjectRef(Sema &S, Expr *E) { + Expr *opaqueRef = E->IgnoreParens(); + if (ObjCPropertyRefExpr *refExpr + = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { + OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBase()); + return ObjCPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E); + } else { + llvm_unreachable("unknown pseudo-object kind!"); + } +} + +/// Given a pseudo-object expression, recreate what it looks like +/// syntactically without the attendant OpaqueValueExprs. +/// +/// This is a hack which should be removed when TreeTransform is +/// capable of rebuilding a tree without stripping implicit +/// operations. +Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) { + Expr *syntax = E->getSyntacticForm(); + if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) { + Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr()); + return new (Context) UnaryOperator(op, uop->getOpcode(), uop->getType(), + uop->getValueKind(), uop->getObjectKind(), + uop->getOperatorLoc()); + } else if (CompoundAssignOperator *cop + = dyn_cast<CompoundAssignOperator>(syntax)) { + Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS()); + Expr *rhs = cast<OpaqueValueExpr>(cop->getRHS())->getSourceExpr(); + return new (Context) CompoundAssignOperator(lhs, rhs, cop->getOpcode(), + cop->getType(), + cop->getValueKind(), + cop->getObjectKind(), + cop->getComputationLHSType(), + cop->getComputationResultType(), + cop->getOperatorLoc()); + } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) { + Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS()); + Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr(); + return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(), + bop->getType(), bop->getValueKind(), + bop->getObjectKind(), + bop->getOperatorLoc()); + } else { + assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject)); + return stripOpaqueValuesFromPseudoObjectRef(*this, syntax); + } +} diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 7c1dafb87ff..d7bdbafaba1 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -6104,8 +6104,14 @@ TreeTransform<Derived>::TransformOpaqueValueExpr(OpaqueValueExpr *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformPseudoObjectExpr(PseudoObjectExpr *E) { - // Rebuild the syntactic form. - ExprResult result = getDerived().TransformExpr(E->getSyntacticForm()); + // Rebuild the syntactic form. The original syntactic form has + // opaque-value expressions in it, so strip those away and rebuild + // the result. This is a really awful way of doing this, but the + // better solution (rebuilding the semantic expressions and + // rebinding OVEs as necessary) doesn't work; we'd need + // TreeTransform to not strip away implicit conversions. + Expr *newSyntacticForm = SemaRef.recreateSyntacticForm(E); + ExprResult result = getDerived().TransformExpr(newSyntacticForm); if (result.isInvalid()) return ExprError(); // If that gives us a pseudo-object result back, the pseudo-object diff --git a/clang/test/CodeGenObjCXX/property-reference.mm b/clang/test/CodeGenObjCXX/property-reference.mm index bc3bb475f5f..63e2be4ba89 100644 --- a/clang/test/CodeGenObjCXX/property-reference.mm +++ b/clang/test/CodeGenObjCXX/property-reference.mm @@ -52,3 +52,45 @@ namespace test1 { // CHECK: call [[A]]* @_ZN5test11AaSERKS0_( // CHECK-NEXT: ret void +// rdar://problem/10497174 +@interface Test2 +@property int prop; +@end + +// The fact that these are all non-dependent is critical. +template <class T> void test2(Test2 *a) { + int x = a.prop; + a.prop = x; + a.prop += x; +} +template void test2<int>(Test2*); +// CHECK: define weak_odr void @_Z5test2IiEvP5Test2( +// CHECK: [[X:%.*]] = alloca i32, +// CHECK: @objc_msgSend +// CHECK: store i32 {{%.*}}, i32* [[X]], +// CHECK: load i32* [[X]], +// CHECK: @objc_msgSend +// CHECK: @objc_msgSend +// CHECK: load i32* [[X]], +// CHECK-NEXT: add nsw +// CHECK: @objc_msgSend +// CHECK-NEXT: ret void + +// Same as the previous test, but instantiation-dependent. +template <class T> void test3(Test2 *a) { + int x = (sizeof(T), a).prop; + a.prop = (sizeof(T), x); + a.prop += (sizeof(T), x); +} +template void test3<int>(Test2*); +// CHECK: define weak_odr void @_Z5test3IiEvP5Test2( +// CHECK: [[X:%.*]] = alloca i32, +// CHECK: @objc_msgSend +// CHECK: store i32 {{%.*}}, i32* [[X]], +// CHECK: load i32* [[X]], +// CHECK: @objc_msgSend +// CHECK: @objc_msgSend +// CHECK: load i32* [[X]], +// CHECK-NEXT: add nsw +// CHECK: @objc_msgSend +// CHECK-NEXT: ret void |

