Переглянути джерело

Preliminary reverse interop support for base classes. (#7059)

Create a Clang AST representation of the base specifier.
Richard Smith 2 тижнів тому
батько
коміт
46f46a538d

+ 4 - 4
toolchain/check/cpp/export.cpp

@@ -261,10 +261,10 @@ static auto BuildCppToCarbonThunkDecl(
   auto* tinfo =
       ast_context.getTrivialTypeSourceInfo(thunk_function_type, clang_loc);
 
-  const bool uses_fp_intrin = false;
-  const bool inline_specified = true;
-  const auto constexpr_kind = clang::ConstexprSpecKind::Unspecified;
-  const auto trailing_requires_clause = clang::AssociatedConstraint();
+  bool uses_fp_intrin = false;
+  bool inline_specified = true;
+  auto constexpr_kind = clang::ConstexprSpecKind::Unspecified;
+  auto trailing_requires_clause = clang::AssociatedConstraint();
 
   clang::FunctionDecl* thunk_function_decl = nullptr;
   if (auto* parent_class = dyn_cast<clang::CXXRecordDecl>(decl_context)) {

+ 28 - 2
toolchain/check/cpp/generate_ast.cpp

@@ -566,9 +566,35 @@ auto CarbonExternalASTSource::CompleteType(clang::TagDecl* tag_decl) -> void {
     return;
   }
 
+  const auto& class_info = context_->classes().Get(class_type->class_id);
   class_decl->startDefinition();
-  // TODO: Import base class and fields, plus any special member functions that
-  // affect class properties.
+  CARBON_CHECK(class_decl->hasDefinition());
+
+  // If the Carbon class has a base class that we can map into C++, add that as
+  // a C++ base class.
+  auto base_type_id =
+      class_info.GetBaseType(context_->sem_ir(), class_type->specific_id);
+  if (base_type_id.has_value()) {
+    auto base_loc = GetCppLocation(*context_, SemIR::LocId(class_info.base_id));
+    if (auto base_type = MapToCppType(*context_, base_type_id);
+        !base_type.isNull() && base_type->isStructureOrClassType() &&
+        !context_->clang_sema().RequireCompleteType(
+            base_loc, base_type, clang::diag::err_incomplete_base_class)) {
+      bool is_virtual = false;
+      bool is_base_of_class = true;
+      clang::CXXBaseSpecifier base(
+          clang::SourceRange(base_loc, base_loc), is_virtual, is_base_of_class,
+          clang::AS_public,
+          context_->ast_context().getTrivialTypeSourceInfo(base_type, base_loc),
+          /*EllipsisLoc=*/clang::SourceLocation());
+      clang::CXXBaseSpecifier* bases[1] = {&base};
+      CARBON_CHECK(class_decl->hasDefinition());
+      class_decl->setBases(bases, 1);
+    }
+  }
+
+  // TODO: Import fields, plus any special member functions that affect class
+  // properties.
   class_decl->completeDefinition();
 }
 

+ 56 - 0
toolchain/check/testdata/interop/cpp/class/export/base.carbon

@@ -0,0 +1,56 @@
+// 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/int.carbon
+//
+// 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/export/base.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/export/base.carbon
+
+// --- derived_to_base.carbon
+library "[[@TEST_NAME]]";
+
+import Cpp;
+
+base class A {}
+
+class B {
+  extend base: A;
+}
+
+inline Cpp '''
+Carbon::A* Convert(Carbon::B* p) {
+  return p;
+}
+''';
+
+// --- name_lookup.carbon
+library "[[@TEST_NAME]]";
+
+import Cpp;
+
+base class A {
+  fn F();
+  fn G(n: i32);
+}
+
+class B {
+  extend base: A;
+  fn G();
+}
+
+inline Cpp '''
+void Qualified() {
+  Carbon::B::F();
+  Carbon::B::G();
+}
+
+void MemberAccess(Carbon::A *a, Carbon::B *b) {
+  // TODO: These cause a crash.
+  // b->F();
+  // b->G();
+}
+''';

+ 120 - 0
toolchain/check/testdata/interop/cpp/class/export/class.carbon

@@ -0,0 +1,120 @@
+// 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/int.carbon
+//
+// 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/export/class.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/export/class.carbon
+
+// --- static_members.carbon
+library "[[@TEST_NAME]]";
+
+import Cpp;
+
+class A {
+  fn F() {}
+}
+
+inline Cpp '''
+void G() {
+  Carbon::A::F();
+}
+''';
+
+// --- nested.carbon
+library "[[@TEST_NAME]]";
+
+import Cpp;
+
+class A {
+  class B {
+    class C {
+    }
+  }
+}
+
+inline Cpp '''
+void G() {
+  Carbon::A::B::C *p = nullptr;
+}
+''';
+
+// --- incomplete.carbon
+library "[[@TEST_NAME]]";
+
+import Cpp;
+
+class A;
+
+inline Cpp '''
+Carbon::A *p = nullptr;
+''';
+
+// --- fail_incomplete_concrete.carbon
+library "[[@TEST_NAME]]";
+
+import Cpp;
+
+// CHECK:STDERR: fail_incomplete_concrete.carbon:[[@LINE+4]]:1: error: class was forward declared here [ClassForwardDeclaredHere]
+// CHECK:STDERR: class A;
+// CHECK:STDERR: ^~~~~~~~
+// CHECK:STDERR:
+class A;
+
+inline Cpp '''
+// CHECK:STDERR: fail_incomplete_concrete.carbon:[[@LINE+4]]:11: error: variable has incomplete type 'Carbon::A' [CppInteropParseError]
+// CHECK:STDERR:    16 | Carbon::A a;
+// CHECK:STDERR:       |           ^
+// CHECK:STDERR:
+Carbon::A a;
+''';
+
+// --- fail_todo_monomorphization_failure.carbon
+library "[[@TEST_NAME]]";
+
+import Cpp;
+
+class B(N:! i32) {
+  var a: array(i8, N);
+}
+
+// TODO: Once we allow this, we should produce an "invalid array bound" error
+// during monomorphization triggered by the C++ code.
+// CHECK:STDERR: fail_todo_monomorphization_failure.carbon:[[@LINE+4]]:11: error: alias initializer must be a name reference [AliasRequiresNameRef]
+// CHECK:STDERR: alias T = B(-1);
+// CHECK:STDERR:           ^~~~~
+// CHECK:STDERR:
+alias T = B(-1);
+
+inline Cpp '''
+// CHECK:STDERR: fail_todo_monomorphization_failure.carbon:[[@LINE+4]]:9: error: no type named 'T' in namespace 'Carbon' [CppInteropParseError]
+// CHECK:STDERR:    22 | Carbon::T t;
+// CHECK:STDERR:       | ~~~~~~~~^
+// CHECK:STDERR:
+Carbon::T t;
+''';
+
+// --- fail_todo_fields.carbon
+library "[[@TEST_NAME]]";
+
+import Cpp;
+
+class A {
+  var a: i32;
+  var b: i32;
+}
+
+inline Cpp '''
+// CHECK:STDERR: fail_todo_fields.carbon:[[@LINE+7]]:15: error: static assertion failed due to requirement 'sizeof(Carbon::A) == 2 * sizeof(int)' [CppInteropParseError]
+// CHECK:STDERR:    18 | static_assert(sizeof(Carbon::A) == 2 * sizeof(int));
+// CHECK:STDERR:       |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR: fail_todo_fields.carbon:[[@LINE+4]]:33: note: expression evaluates to '1 == 8' [CppInteropParseNote]
+// CHECK:STDERR:    18 | static_assert(sizeof(Carbon::A) == 2 * sizeof(int));
+// CHECK:STDERR:       |               ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+static_assert(sizeof(Carbon::A) == 2 * sizeof(int));
+''';

+ 2 - 2
toolchain/check/testdata/interop/cpp/class/abstract.carbon → toolchain/check/testdata/interop/cpp/class/import/abstract.carbon

@@ -7,9 +7,9 @@
 //
 // 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/abstract.carbon
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/import/abstract.carbon
 // TIP: To dump output, run:
-// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/abstract.carbon
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/import/abstract.carbon
 
 // --- abstract.h
 

+ 2 - 2
toolchain/check/testdata/interop/cpp/class/access.carbon → toolchain/check/testdata/interop/cpp/class/import/access.carbon

@@ -6,9 +6,9 @@
 //
 // 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/access.carbon
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/import/access.carbon
 // TIP: To dump output, run:
-// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/access.carbon
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/import/access.carbon
 
 // ============================================================================
 // Public non-function member

+ 2 - 2
toolchain/check/testdata/interop/cpp/class/base.carbon → toolchain/check/testdata/interop/cpp/class/import/base.carbon

@@ -6,9 +6,9 @@
 //
 // 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/base.carbon
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/import/base.carbon
 // TIP: To dump output, run:
-// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/base.carbon
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/import/base.carbon
 
 // --- derived_to_base_conversion.h
 

+ 2 - 2
toolchain/check/testdata/interop/cpp/class/class.carbon → toolchain/check/testdata/interop/cpp/class/import/class.carbon

@@ -6,9 +6,9 @@
 //
 // 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/class.carbon
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/import/class.carbon
 // TIP: To dump output, run:
-// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/class.carbon
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/import/class.carbon
 
 // ============================================================================
 // Declaration

+ 2 - 2
toolchain/check/testdata/interop/cpp/class/constructor.carbon → toolchain/check/testdata/interop/cpp/class/import/constructor.carbon

@@ -6,9 +6,9 @@
 //
 // 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/constructor.carbon
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/import/constructor.carbon
 // TIP: To dump output, run:
-// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/constructor.carbon
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/import/constructor.carbon
 
 // ============================================================================
 // Default constructor

+ 2 - 2
toolchain/check/testdata/interop/cpp/class/field.carbon → toolchain/check/testdata/interop/cpp/class/import/field.carbon

@@ -6,9 +6,9 @@
 //
 // 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/field.carbon
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/import/field.carbon
 // TIP: To dump output, run:
-// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/field.carbon
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/import/field.carbon
 
 // --- struct.h
 

+ 2 - 2
toolchain/check/testdata/interop/cpp/class/invalid.carbon → toolchain/check/testdata/interop/cpp/class/import/invalid.carbon

@@ -6,9 +6,9 @@
 //
 // 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/invalid.carbon
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/import/invalid.carbon
 // TIP: To dump output, run:
-// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/invalid.carbon
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/import/invalid.carbon
 
 // --- fail_invalid_base.carbon
 

+ 2 - 2
toolchain/check/testdata/interop/cpp/class/method.carbon → toolchain/check/testdata/interop/cpp/class/import/method.carbon

@@ -7,9 +7,9 @@
 //
 // 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/method.carbon
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/import/method.carbon
 // TIP: To dump output, run:
-// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/method.carbon
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/import/method.carbon
 
 // --- object_param_qualifiers.h
 

+ 2 - 2
toolchain/check/testdata/interop/cpp/class/nested.carbon → toolchain/check/testdata/interop/cpp/class/import/nested.carbon

@@ -6,9 +6,9 @@
 //
 // 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/nested.carbon
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/import/nested.carbon
 // TIP: To dump output, run:
-// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/nested.carbon
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/import/nested.carbon
 
 // --- import_nested_class.carbon
 

+ 2 - 2
toolchain/check/testdata/interop/cpp/class/non_aggregate_init.carbon → toolchain/check/testdata/interop/cpp/class/import/non_aggregate_init.carbon

@@ -7,9 +7,9 @@
 //
 // 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:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/import/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
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/import/non_aggregate_init.carbon
 
 // ============================================================================
 // Non-aggregate class should not be initializable from {}

+ 2 - 2
toolchain/check/testdata/interop/cpp/class/struct.carbon → toolchain/check/testdata/interop/cpp/class/import/struct.carbon

@@ -6,9 +6,9 @@
 //
 // 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/struct.carbon
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/import/struct.carbon
 // TIP: To dump output, run:
-// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/struct.carbon
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/import/struct.carbon
 
 // ============================================================================
 // Declaration

+ 2 - 2
toolchain/check/testdata/interop/cpp/class/template.carbon → toolchain/check/testdata/interop/cpp/class/import/template.carbon

@@ -6,9 +6,9 @@
 //
 // 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/template.carbon
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/import/template.carbon
 // TIP: To dump output, run:
-// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/template.carbon
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/import/template.carbon
 
 // --- class_template.h
 

+ 2 - 2
toolchain/check/testdata/interop/cpp/class/union.carbon → toolchain/check/testdata/interop/cpp/class/import/union.carbon

@@ -6,9 +6,9 @@
 //
 // 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/union.carbon
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/import/union.carbon
 // TIP: To dump output, run:
-// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/union.carbon
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/import/union.carbon
 
 // ============================================================================
 // Declaration