]> granicus.if.org Git - clang/commitdiff
Fix the instantiation of pseudo-object expressions. This is a
authorJohn McCall <rjmccall@apple.com>
Wed, 30 Nov 2011 04:42:31 +0000 (04:42 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 30 Nov 2011 04:42:31 +0000 (04:42 +0000)
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

include/clang/Sema/Sema.h
lib/Sema/SemaPseudoObject.cpp
lib/Sema/TreeTransform.h
test/CodeGenObjCXX/property-reference.mm

index 66d0baf73b22dd05bd5de6dbeaa0db81625d4121..eccde04aff5290a3948a67bc9d6f5d9d0d68f0d7 100644 (file)
@@ -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,
index 3bd671d10cd0745507d14c03eda3eaa42b39d7e9..08b3fc82ca3402745be571b6764dcc796546af16 100644 (file)
@@ -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);
+  }
+}
index 7c1dafb87ffa4ba5a0ce971666513f7c5b969bc1..d7bdbafaba196189d97509a2dcd61f2ea3c45b1e 100644 (file)
@@ -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
index bc3bb475f5f78cb4842b5d04196e4f15bfbb1260..63e2be4ba89560ef69e8e3a7e72110a6bcb373e0 100644 (file)
@@ -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