Skip to content

Commit 805600d

Browse files
authored
C++ Interop: Preserve non-nullability when mapping const non-nullable pointers (#6293)
For non-nullable const pointers, we need to keep the non-nullability. This is done by preserving non-nullability when mapping qualifiers.
1 parent 114ecda commit 805600d

File tree

2 files changed

+554
-54
lines changed

2 files changed

+554
-54
lines changed

toolchain/check/cpp/import.cpp

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,26 @@ static auto MapQualifiedType(Context& context, clang::QualType type,
12191219
return type_expr;
12201220
}
12211221

1222+
// Returns true if the type has the `_Nonnull` attribute.
1223+
static auto IsClangTypeNonNull(clang::QualType type) -> bool {
1224+
auto nullability = type->getNullability();
1225+
return nullability.has_value() &&
1226+
*nullability == clang::NullabilityKind::NonNull;
1227+
}
1228+
1229+
// Like `clang::QualType::getUnqualifiedType()`, retrieves the unqualified
1230+
// variant of the given type, but preserves `_Nonnull`.
1231+
static auto ClangGetUnqualifiedTypePreserveNonNull(
1232+
Context& context, clang::QualType original_type) -> clang::QualType {
1233+
clang::QualType type = original_type.getUnqualifiedType();
1234+
// Preserve non-nullability.
1235+
if (IsClangTypeNonNull(original_type) && !IsClangTypeNonNull(type)) {
1236+
type = context.ast_context().getAttributedType(
1237+
clang::NullabilityKind::NonNull, type, type);
1238+
}
1239+
return type;
1240+
}
1241+
12221242
// Returns the type `Core.Optional(T)`, where `T` is described by
12231243
// `inner_type_inst_id`.
12241244
static auto MakeOptionalType(Context& context, SemIR::LocId loc_id,
@@ -1234,16 +1254,11 @@ static auto MapPointerType(Context& context, SemIR::LocId loc_id,
12341254
-> TypeExpr {
12351255
CARBON_CHECK(type->isPointerType());
12361256

1237-
bool optional = false;
1238-
if (auto nullability = type->getNullability();
1239-
!nullability.has_value() ||
1240-
*nullability != clang::NullabilityKind::NonNull) {
1241-
// If the type was produced by C++ template substitution, then we assume it
1242-
// was deduced from a Carbon pointer type, so it's non-null.
1243-
if (!type->getAs<clang::SubstTemplateTypeParmType>()) {
1244-
optional = true;
1245-
}
1246-
}
1257+
bool optional =
1258+
!IsClangTypeNonNull(type) &&
1259+
// If the type was produced by C++ template substitution, then we assume
1260+
// it was deduced from a Carbon pointer type, so it's non-null.
1261+
!type->getAs<clang::SubstTemplateTypeParmType>();
12471262

12481263
TypeExpr pointer_type_expr = TypeExpr::ForUnsugared(
12491264
context, GetPointerType(context, pointee_type_expr.inst_id));
@@ -1278,7 +1293,7 @@ static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type)
12781293
while (true) {
12791294
clang::QualType orig_type = type;
12801295
if (type.hasQualifiers()) {
1281-
type = type.getUnqualifiedType();
1296+
type = ClangGetUnqualifiedTypePreserveNonNull(context, type);
12821297
} else if (type->isPointerType()) {
12831298
type = type->getPointeeType();
12841299
} else if (type->isReferenceType()) {
@@ -1451,10 +1466,8 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
14511466
// The parameter type is decayed but hasn't necessarily had its qualifiers
14521467
// removed.
14531468
// TODO: The presence of qualifiers here is probably a Clang bug.
1454-
// TODO: For const non nullable pointers (`C* _Nonnull const`), this removes
1455-
// both the const and the non-nullable attribute. We should probably
1456-
// preserve the non-nullable attribute.
1457-
clang::QualType param_type = orig_param_type.getUnqualifiedType();
1469+
clang::QualType param_type =
1470+
ClangGetUnqualifiedTypePreserveNonNull(context, orig_param_type);
14581471

14591472
// Mark the start of a region of insts, needed for the type expression
14601473
// created later with the call of `EndSubpatternAsExpr()`.

0 commit comments

Comments
 (0)