diff --git a/src/lower_il.c b/src/lower_il.c index 34ee33cb6f..4493746e7b 100644 --- a/src/lower_il.c +++ b/src/lower_il.c @@ -1182,20 +1182,19 @@ offset for the field. /* Store the base class name. */ (void)strcpy(name_ptr+prefix_length, temp_name); /* Create the field. */ -#if IA64_ABI field_ptr = add_field(name_ptr, field_type, field_offset, struct_type, /*for_base_class=*/TRUE); - if (targ_reuse_tail_padding && is_immediate_class_type(field_type) && + if ( +#if IA64_ABI + targ_reuse_tail_padding && +#endif /* IA64_ABI */ + is_immediate_class_type(field_type) && class_type_supp(field_type)->compiler_generated && (field_type->size % field_type->alignment) != 0) { /* There is padding at the end of the base class subobject in which derived class members may be allocated. */ field_ptr->class_subobject_with_tail_padding = TRUE; } /* if */ -#else /* !IA64_ABI */ - field_ptr = add_field(name_ptr, field_type, field_offset, struct_type, - /*for_base_class=*/TRUE); -#endif /* IA64_ABI */ field_ptr->is_lowered_base_class = TRUE; } /* add_base_class_dummy_field */ @@ -8534,13 +8533,21 @@ this routine to do a relatively simple copy of all the fields. ctsp = class_type->variant.class_struct_union.extra_info; if ((!class_type->variant.class_struct_union.any_virtual_base_classes +#if !IA64_ABI + /* The size as a base can still be smaller than the size of the class + (in Microsoft mode, which ignores some alignment requirements when + computing the size of a base class). */ + && (type_is(class_type, tk_union) || + ctsp->size_without_virtual_base_classes == class_type->size) +#endif /* !IA64_ABI */ #if CFRONT_OBJECT_CODE_COMPATIBILITY - || !class_has_independently_allocated_virtual_base_classes(class_type) + || (class_type->variant.class_struct_union.any_virtual_base_classes && + !class_has_independently_allocated_virtual_base_classes(class_type)) #endif /* CFRONT_OBJECT_CODE_COMPATIBILITY */ ) #if IA64_ABI && (!targ_reuse_tail_padding || - class_type->kind == (a_type_kind)tk_union || + type_is(class_type, tk_union) || ctsp->size_without_virtual_base_classes == class_type->size) #endif /* IA64_ABI */ ) { @@ -10020,7 +10027,7 @@ Do IL lowering of the indicated field and everything under it. mark_as_visited(field); lower_source_correspondence(&field->source_corresp); lower_os_type(field->type); -#if BACK_END_IS_C_GEN_BE && IA64_ABI && MAINTAIN_NEEDED_FLAGS +#if BACK_END_IS_C_GEN_BE && MAINTAIN_NEEDED_FLAGS if (field->class_subobject_with_tail_padding) { /* Ensure that the corresponding subobject type definition is not removed from the IL, as it will be needed by the C-generating back @@ -10031,7 +10038,7 @@ Do IL lowering of the indicated field and everything under it. class_type_supp(ftp)->subobject_partner-> variant.class_struct_union.keep_definition_in_il = TRUE; } /* if */ -#endif /* BACK_END_IS_C_GEN_BE && IA64_ABI && MAINTAIN_NEEDED_FLAGS */ +#endif /* BACK_END_IS_C_GEN_BE && MAINTAIN_NEEDED_FLAGS */ } /* if */ } /* lower_field */ diff --git a/src/pending_changes/gh-479-lowered-base-class-size-without-ia64-abi.txt b/src/pending_changes/gh-479-lowered-base-class-size-without-ia64-abi.txt new file mode 100644 index 0000000000..96b89a879c --- /dev/null +++ b/src/pending_changes/gh-479-lowered-base-class-size-without-ia64-abi.txt @@ -0,0 +1,18 @@ +[GH #479] +Lowered layout of Microsoft-mode base classes without the IA-64 ABI + +In front ends configured with IA64_ABI set to FALSE, IL lowering did not +account for the padding at the end of a base class subobject. In Microsoft +mode, a base class whose alignment is stricter than the platform default +can occupy less space as a base class subobject than its full size, so +later members of the derived class are allocated in what would otherwise be +its tail padding. IL lowering nonetheless emitted such a base class as a +field of the complete base class type, so the C compiler placed the derived +class members at larger offsets than the front end had computed (e.g., than +those used for sizeof and offsetof). Such a base class is now +lowered to a type-as-subobject whose members are emitted inline, as is done +for IA-64 ABI configurations. For example, with --ms_c++20: + + struct B { alignas(16) char arr[2]; }; + struct D : B { char d; }; // d is at offset 8. + void f(D *p) { p->d = 'x'; } // Previously accessed offset 16. diff --git a/tests/tests/regressions/.gh-479.rto/default.1.1.txt b/tests/tests/regressions/.gh-479.rto/default.1.1.txt new file mode 100644 index 0000000000..9de71c7b9b --- /dev/null +++ b/tests/tests/regressions/.gh-479.rto/default.1.1.txt @@ -0,0 +1,5 @@ +eccp -DTEST_NUMBER=1 --c++11 --g++ --gnu_version=150200 Test_name.c +"Test_name.c", line 13: warning: offsetof applied to a type other than a standard-layout class + long fe_offset = __builtin_offsetof(D, d); // Front end's layout. + ^ + diff --git a/tests/tests/regressions/.gh-479.rto/default.1.2.txt b/tests/tests/regressions/.gh-479.rto/default.1.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/regressions/.gh-479.rto/default.1.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/regressions/.gh-479.rto/default.2.1.txt b/tests/tests/regressions/.gh-479.rto/default.2.1.txt new file mode 100644 index 0000000000..c915171df0 --- /dev/null +++ b/tests/tests/regressions/.gh-479.rto/default.2.1.txt @@ -0,0 +1,5 @@ +eccp -DTEST_NUMBER=2 --c++20 --clang --clang_version=210000 Test_name.c +"Test_name.c", line 13: warning: offsetof applied to a type other than a standard-layout class + long fe_offset = __builtin_offsetof(D, d); // Front end's layout. + ^ + diff --git a/tests/tests/regressions/.gh-479.rto/default.2.2.txt b/tests/tests/regressions/.gh-479.rto/default.2.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/regressions/.gh-479.rto/default.2.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/regressions/.gh-479.rto/default.3.1.txt b/tests/tests/regressions/.gh-479.rto/default.3.1.txt new file mode 100644 index 0000000000..d4af7abaea --- /dev/null +++ b/tests/tests/regressions/.gh-479.rto/default.3.1.txt @@ -0,0 +1,5 @@ +eccp -DTEST_NUMBER=3 --ms_c++20 --microsoft_version 1950 Test_name.c +"Test_name.c", line 13: warning: offsetof applied to a type other than a standard-layout class + long fe_offset = __builtin_offsetof(D, d); // Front end's layout. + ^ + diff --git a/tests/tests/regressions/.gh-479.rto/default.3.2.txt b/tests/tests/regressions/.gh-479.rto/default.3.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/regressions/.gh-479.rto/default.3.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/regressions/gh-479.sft.cpp b/tests/tests/regressions/gh-479.sft.cpp new file mode 100644 index 0000000000..18fd0cc5a1 --- /dev/null +++ b/tests/tests/regressions/gh-479.sft.cpp @@ -0,0 +1,16 @@ +//type:rp +//options:--c++11 --g++ --gnu_version=150200:--c++20 --clang --clang_version=210000:--ms_c++20 --microsoft_version 1950 +// A base class whose alignment requirement leaves padding at the end of the +// base class subobject must have that padding accounted for when IL lowering +// places the members of a derived class. The offset of "d" in the lowered +// code must match the offset computed by the front end. + +struct B { alignas(16) char c; }; +struct D : B { char d; }; + +int main() { + D x; + long fe_offset = __builtin_offsetof(D, d); // Front end's layout. + long be_offset = (char *)&x.d - (char *)&x; // Lowered C's layout. + return fe_offset != be_offset; +}