]> granicus.if.org Git - clang/commitdiff
Fix argument expansion of reference fields of structs
authorReid Kleckner <rnk@google.com>
Mon, 2 May 2016 22:42:34 +0000 (22:42 +0000)
committerReid Kleckner <rnk@google.com>
Mon, 2 May 2016 22:42:34 +0000 (22:42 +0000)
r268261 made Clang "expand" more struct arguments on Windows. It removed
the check for 'RD->isCLike()', which was preventing us from attempting
to expand structs with reference type fields.

Our expansion code was attempting to load and pass each field of the
type in turn. We were accidentally doing one to many loads on reference
type fields.

On the function prologue side, we can use
EmitLValueForFieldInitialization, which obviously gets the address of
the field. On the call side, I tweaked EmitRValueForField directly,
since this is the only use of this method.

Fixes PR27607

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@268321 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCall.cpp
lib/CodeGen/CGExpr.cpp
test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp

index 04c0a116001d10bdd778fa3406cb39c2b0d9f9a8..50ea7f7cc337a8bc8a5cfcbba6079223ee97064f 100644 (file)
@@ -948,7 +948,7 @@ void CodeGenFunction::ExpandTypeFromArgs(
     }
     for (auto FD : RExp->Fields) {
       // FIXME: What are the right qualifiers here?
-      LValue SubLV = EmitLValueForField(LV, FD);
+      LValue SubLV = EmitLValueForFieldInitialization(LV, FD);
       ExpandTypeFromArgs(FD->getType(), SubLV, AI);
     }
   } else if (isa<ComplexExpansion>(Exp.get())) {
index 8329e52bde3044514f464d805ddca4ce68a86f73..3ecd8e3f0f6c1d7437824400e67106e5ef39e8a1 100644 (file)
@@ -3667,6 +3667,10 @@ RValue CodeGenFunction::EmitRValueForField(LValue LV,
   case TEK_Aggregate:
     return FieldLV.asAggregateRValue();
   case TEK_Scalar:
+    // This routine is used to load fields one-by-one to perform a copy, so
+    // don't load reference fields.
+    if (FD->getType()->isReferenceType())
+      return RValue::get(FieldLV.getPointer());
     return EmitLoadOfLValue(FieldLV, Loc);
   }
   llvm_unreachable("bad evaluation kind");
index a5cb98d41b203d7996a5c5e2fe5e4c1ff7b60584..f7dc52406740635b00c5be33f6278ecd91c2af65 100644 (file)
@@ -217,6 +217,28 @@ void big_arg(Big s) {}
 // WIN32: define void @"\01?big_arg@@YAXUBig@@@Z"(%struct.Big* byval align 4 %s)
 // WIN64: define void @"\01?big_arg@@YAXUBig@@@Z"(%struct.Big* %s)
 
+// PR27607: We would attempt to load i32 value out of the reference instead of
+// just loading the pointer from the struct during argument expansion.
+struct RefField {
+  RefField(int &x);
+  int &x;
+};
+void takes_ref_field(RefField s) {}
+// LINUX-LABEL: define void @_Z15takes_ref_field8RefField(%struct.RefField* byval align 4 %s)
+// WIN32: define void @"\01?takes_ref_field@@YAXURefField@@@Z"(i32* %s.0)
+// WIN64: define void @"\01?takes_ref_field@@YAXURefField@@@Z"(i64 %s.coerce)
+
+void pass_ref_field() {
+  int x;
+  takes_ref_field(RefField(x));
+}
+// LINUX-LABEL: define void @_Z14pass_ref_fieldv()
+// LINUX: call void @_Z15takes_ref_field8RefField(%struct.RefField* byval align 4 %{{.*}})
+// WIN32-LABEL: define void @"\01?pass_ref_field@@YAXXZ"()
+// WIN32: call void @"\01?takes_ref_field@@YAXURefField@@@Z"(i32* %{{.*}})
+// WIN64-LABEL: define void @"\01?pass_ref_field@@YAXXZ"()
+// WIN64: call void @"\01?takes_ref_field@@YAXURefField@@@Z"(i64 %{{.*}})
+
 class Class {
  public:
   Small thiscall_method_small() { return Small(); }