diff options
| -rw-r--r-- | clang/lib/CodeGen/CGCall.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 4 | ||||
| -rw-r--r-- | clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp | 22 |
3 files changed, 27 insertions, 1 deletions
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 04c0a116001..50ea7f7cc33 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -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())) { diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 8329e52bde3..3ecd8e3f0f6 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -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"); diff --git a/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp b/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp index a5cb98d41b2..f7dc5240674 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp @@ -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(); } |

