mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-02 17:52:58 +01:00
Support importing C++ _Nonnull pointers as function parameters or return values (#5773)
We avoid using canonical type before knowing it's not a pointer because
we need the nullability attribute.
No support for pointers to pointers, yet.
C++ Interop Demo:
```c++
// hello_world.h
auto hello_world_param(int* _Nonnull i) -> void;
auto hello_world_return() -> int* _Nonnull;
```
```c++
// hello_world.cpp
#include "hello_world.h"
#include <cstdio>
auto hello_world_param(int* _Nonnull i) -> void {
printf("hello_world: %d\n", *i);
}
static int x = 5;
auto hello_world_return() -> int* _Nonnull { return &x; }
```
```carbon
// main.carbon
library "Main";
import Core library "io";
import Cpp library "hello_world.h";
fn Run() -> i32 {
var i: i32 = 10;
Cpp.hello_world_param(&i);
let p: i32* = Cpp.hello_world_return();
Core.Print(*p);
return 0;
}
```
```shell
$ clang -c hello_world.cpp
$ ./bazel-bin/toolchain/install/prefix_root/bin/carbon compile main.carbon
$ ./bazel-bin/toolchain/install/prefix_root/bin/carbon link hello_world.o main.o --output=demo
$ ./demo
hello_world: 10
5
```
Part of #5772.
This commit is contained in:
@@ -700,10 +700,13 @@ static auto MapRecordType(Context& context, SemIR::LocId loc_id,
|
||||
.type_id = SemIR::ErrorInst::TypeId};
|
||||
}
|
||||
|
||||
// Maps a C++ type to a Carbon type.
|
||||
// Maps a C++ non-pointer type to a Carbon type.
|
||||
// TODO: Support more types.
|
||||
static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type)
|
||||
-> TypeExpr {
|
||||
static auto MapNonPointerType(Context& context, SemIR::LocId loc_id,
|
||||
clang::QualType type) -> TypeExpr {
|
||||
type = type.getCanonicalType();
|
||||
CARBON_CHECK(!type->isPointerType());
|
||||
|
||||
if (const auto* builtin_type = dyn_cast<clang::BuiltinType>(type)) {
|
||||
return MapBuiltinType(context, *builtin_type);
|
||||
}
|
||||
@@ -716,6 +719,54 @@ static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type)
|
||||
.type_id = SemIR::ErrorInst::TypeId};
|
||||
}
|
||||
|
||||
// Maps a C++ pointer type to a Carbon pointer type.
|
||||
static auto MapPointerType(Context& context, SemIR::LocId loc_id,
|
||||
clang::QualType type) -> TypeExpr {
|
||||
CARBON_CHECK(type->isPointerType());
|
||||
|
||||
if (auto nullability = type->getNullability();
|
||||
!nullability.has_value() ||
|
||||
*nullability != clang::NullabilityKind::NonNull) {
|
||||
context.TODO(loc_id, llvm::formatv("Unsupported: nullable pointer: {0}",
|
||||
type.getAsString()));
|
||||
return {.inst_id = SemIR::ErrorInst::TypeInstId,
|
||||
.type_id = SemIR::ErrorInst::TypeId};
|
||||
}
|
||||
|
||||
clang::QualType pointee_type = type->getPointeeType();
|
||||
|
||||
if (pointee_type->isAnyPointerType()) {
|
||||
context.TODO(loc_id,
|
||||
llvm::formatv("Unsupported: pointer to pointer type: {0}",
|
||||
pointee_type.getAsString()));
|
||||
return {.inst_id = SemIR::ErrorInst::TypeInstId,
|
||||
.type_id = SemIR::ErrorInst::TypeId};
|
||||
}
|
||||
|
||||
TypeExpr pointee_type_expr = MapNonPointerType(context, loc_id, pointee_type);
|
||||
if (pointee_type_expr.inst_id == SemIR::ErrorInst::InstId ||
|
||||
pointee_type_expr.type_id == SemIR::ErrorInst::TypeId) {
|
||||
return {.inst_id = SemIR::ErrorInst::TypeInstId,
|
||||
.type_id = SemIR::ErrorInst::TypeId};
|
||||
}
|
||||
|
||||
SemIR::TypeId pointer_type_id =
|
||||
GetPointerType(context, pointee_type_expr.inst_id);
|
||||
return {.inst_id = context.types().GetInstId(pointer_type_id),
|
||||
.type_id = pointer_type_id};
|
||||
}
|
||||
|
||||
// Maps a C++ type to a Carbon type. `type` should not be canonicalized because
|
||||
// we check for pointer nullability and nullability will be lost by
|
||||
// canonicalization.
|
||||
static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type)
|
||||
-> TypeExpr {
|
||||
if (type->isPointerType()) {
|
||||
return MapPointerType(context, loc_id, type);
|
||||
}
|
||||
return MapNonPointerType(context, loc_id, type);
|
||||
}
|
||||
|
||||
// Returns a block id for the explicit parameters of the given function
|
||||
// declaration. If the function declaration has no parameters, it returns
|
||||
// `SemIR::InstBlockId::Empty`. In the case of an unsupported parameter type, it
|
||||
@@ -731,7 +782,7 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
|
||||
llvm::SmallVector<SemIR::InstId> params;
|
||||
params.reserve(clang_decl.parameters().size());
|
||||
for (const clang::ParmVarDecl* param : clang_decl.parameters()) {
|
||||
clang::QualType param_type = param->getType().getCanonicalType();
|
||||
clang::QualType param_type = param->getType();
|
||||
|
||||
// Mark the start of a region of insts, needed for the type expression
|
||||
// created later with the call of `EndSubpatternAsExpr()`.
|
||||
@@ -784,7 +835,7 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
|
||||
static auto GetReturnType(Context& context, SemIR::LocId loc_id,
|
||||
const clang::FunctionDecl* clang_decl)
|
||||
-> SemIR::InstId {
|
||||
clang::QualType ret_type = clang_decl->getReturnType().getCanonicalType();
|
||||
clang::QualType ret_type = clang_decl->getReturnType();
|
||||
if (ret_type->isVoidType()) {
|
||||
return SemIR::InstId::None;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user