@@ -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`.
12241244static 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