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 | 01e19be69a37bc4ab7746c454cfaa6aec7bb7c6a (patch) | |
tree | b1377912619595dcaab8dcfaad543ab3b66ce6eb | |
parent | a8cc6ce36e70e2afa22ab6b4340035cb3941c2eb (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145480 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Sema/Sema.h | 2 | ||||
-rw-r--r-- | lib/Sema/SemaPseudoObject.cpp | 51 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 10 | ||||
-rw-r--r-- | test/CodeGenObjCXX/property-reference.mm | 42 |
4 files changed, 103 insertions, 2 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 66d0baf73b..eccde04aff 100644 --- a/include/clang/Sema/Sema.h +++ b/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/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index 3bd671d10c..08b3fc82ca 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/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/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 7c1dafb87f..d7bdbafaba 100644 --- a/lib/Sema/TreeTransform.h +++ b/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/test/CodeGenObjCXX/property-reference.mm b/test/CodeGenObjCXX/property-reference.mm index bc3bb475f5..63e2be4ba8 100644 --- a/test/CodeGenObjCXX/property-reference.mm +++ b/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 |