mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 22:02:52 +01:00
## Summary
Fixes the toolchain incorrectly allowing `{}` initialization for
non-aggregate C++ classes.
## Problem
When importing an empty C++ class, the toolchain was treating it as a
Carbon empty struct, which allowed initialization from `{}`. This is
incorrect for non-aggregate classes (e.g., those with user-declared
constructors).
```carbon
import Cpp inline '''
struct X { X(); }; // non-aggregate (has user-declared constructor)
''';
fn Make() {
var x: Cpp.X = {}; // incorrectly accepted, should be rejected
}
```
## Solution
Added a check for `clang_def->isAggregate()` in `ImportClassObjectRepr`
so that only aggregate classes get the empty struct representation.
**Before:**
```cpp
if (clang_def->isEmpty() && !clang_def->getNumBases()) {
```
**After:**
```cpp
if (clang_def->isEmpty() && !clang_def->getNumBases() &&
clang_def->isAggregate()) {
```
## Testing
Added test file
`toolchain/check/testdata/interop/cpp/class/non_aggregate_init.carbon`
with:
- Non-aggregate class (`struct X { X(); }`) - should reject `{}`
initialization
- Aggregate class (`struct Y {}`) - should accept `{}` initialization
Note: I couldn't run tests locally due to clang version requirements
(needs >= 19, have 17). The CI should validate the changes.
Closes #6669
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
61 lines
2.1 KiB
Plaintext
61 lines
2.1 KiB
Plaintext
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/primitives.carbon
|
|
// EXTRA-ARGS: --target=x86_64-linux-gnu --clang-arg=-std=c++20
|
|
//
|
|
// AUTOUPDATE
|
|
// TIP: To test this file alone, run:
|
|
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/non_aggregate_init.carbon
|
|
// TIP: To dump output, run:
|
|
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/non_aggregate_init.carbon
|
|
|
|
// ============================================================================
|
|
// Non-aggregate class should not be initializable from {}
|
|
// ============================================================================
|
|
|
|
// --- non_aggregate.h
|
|
|
|
// A class with a user-declared constructor is not an aggregate.
|
|
struct X {
|
|
X();
|
|
};
|
|
|
|
// --- fail_non_aggregate_init.carbon
|
|
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import Cpp library "non_aggregate.h";
|
|
|
|
fn Make() {
|
|
// CHECK:STDERR: fail_non_aggregate_init.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `{}` to `Cpp.X` [ConversionFailure]
|
|
// CHECK:STDERR: var _: Cpp.X = {};
|
|
// CHECK:STDERR: ^~~~~~~~~~~~
|
|
// CHECK:STDERR: fail_non_aggregate_init.carbon:[[@LINE+4]]:3: note: type `{}` does not implement interface `Core.ImplicitAs(Cpp.X)` [MissingImplInMemberAccessNote]
|
|
// CHECK:STDERR: var _: Cpp.X = {};
|
|
// CHECK:STDERR: ^~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
var _: Cpp.X = {};
|
|
}
|
|
|
|
// ============================================================================
|
|
// Aggregate class should be initializable from {}
|
|
// ============================================================================
|
|
|
|
// --- aggregate.h
|
|
|
|
// A class with no user-declared constructors is an aggregate.
|
|
struct Y {};
|
|
|
|
// --- aggregate_init.carbon
|
|
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import Cpp library "aggregate.h";
|
|
|
|
fn Make() {
|
|
// This should succeed because Y is an aggregate.
|
|
var _: Cpp.Y = {};
|
|
}
|