diff options
author | Longsheng Mou <moulongsheng@huawei.com> | 2024-04-03 19:12:12 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-03 19:12:12 +0800 |
commit | 956b47b48616148c15f8f95d76d5e0c215fe095c (patch) | |
tree | c77f658d68b2347fc6d1d7250b2bb6d3e98f9a76 | |
parent | 1f268092c7af20c21d4a594678b647cab050602a (diff) | |
download | llvm-956b47b48616148c15f8f95d76d5e0c215fe095c.zip llvm-956b47b48616148c15f8f95d76d5e0c215fe095c.tar.gz llvm-956b47b48616148c15f8f95d76d5e0c215fe095c.tar.bz2 |
[X86_32] Teach X86_32 va_arg to ignore empty structs. (#86075)
Empty structs are ignored for parameter passing purposes, but va_arg was
incrementing the pointer anyway for that the size of empty struct in c++
is 1 byte, which could lead to va_list getting out of sync. Fix #86057.
-rw-r--r-- | clang/lib/CodeGen/Targets/X86.cpp | 6 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/x86_32-vaarg.cpp | 21 |
2 files changed, 27 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp index 1146a85..c831777 100644 --- a/clang/lib/CodeGen/Targets/X86.cpp +++ b/clang/lib/CodeGen/Targets/X86.cpp @@ -1069,6 +1069,12 @@ Address X86_32ABIInfo::EmitVAArg(CodeGenFunction &CGF, auto TypeInfo = getContext().getTypeInfoInChars(Ty); + CCState State(*const_cast<CGFunctionInfo *>(CGF.CurFnInfo)); + ABIArgInfo AI = classifyArgumentType(Ty, State, /*ArgIndex*/ 0); + // Empty records are ignored for parameter passing purposes. + if (AI.isIgnore()) + return CGF.CreateMemTemp(Ty); + // x86-32 changes the alignment of certain arguments on the stack. // // Just messing with TypeInfo like this works because we never pass diff --git a/clang/test/CodeGenCXX/x86_32-vaarg.cpp b/clang/test/CodeGenCXX/x86_32-vaarg.cpp new file mode 100644 index 0000000..dcc2f7f --- /dev/null +++ b/clang/test/CodeGenCXX/x86_32-vaarg.cpp @@ -0,0 +1,21 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -triple i386-linux-gnu -emit-llvm -o - %s | FileCheck %s + +typedef struct {} empty; + +// CHECK-LABEL: @_Z17empty_record_testiz( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[Z_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[LIST:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[TMP:%.*]] = alloca [[STRUCT_EMPTY:%.*]], align 1 +// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 +// CHECK-NEXT: store i32 [[Z:%.*]], ptr [[Z_ADDR]], align 4 +// CHECK-NEXT: call void @llvm.va_start.p0(ptr [[LIST]]) +// CHECK-NEXT: ret void +// +empty empty_record_test(int z, ...) { + __builtin_va_list list; + __builtin_va_start(list, z); + return __builtin_va_arg(list, empty); +} |