@@ -1212,8 +1212,7 @@ static auto MapQualifiedType(Context& context, clang::QualType type,
12121212
12131213 if (quals.hasConst ()) {
12141214 auto type_id = GetConstType (context, type_expr.inst_id );
1215- type_expr = {.inst_id = context.types ().GetInstId (type_id),
1216- .type_id = type_id};
1215+ type_expr = TypeExpr::ForUnsugared (context, type_id);
12171216 quals.removeConst ();
12181217 }
12191218
@@ -1260,19 +1259,18 @@ static auto MapPointerType(Context& context, SemIR::LocId loc_id,
12601259 return pointer_type_expr;
12611260}
12621261
1263- // Maps a C++ reference type to a Carbon type.
1264- // We map `T&` to `T*`, and `T&&` to `T`.
1262+ // Maps a C++ reference type to a Carbon type. We map all references to
1263+ // pointers for now. Note that when mapping function parameters and return
1264+ // types, a different rule is used; see MapParameterType for details.
12651265// TODO: Revisit this and decide what we really want to do here.
12661266static auto MapReferenceType (Context& context, clang::QualType type,
12671267 TypeExpr referenced_type_expr) -> TypeExpr {
12681268 CARBON_CHECK (type->isReferenceType ());
1269-
1270- if (!type->isLValueReferenceType ()) {
1271- return referenced_type_expr;
1272- }
1273-
1274- return TypeExpr::ForUnsugared (
1275- context, GetPointerType (context, referenced_type_expr.inst_id ));
1269+ SemIR::TypeId pointer_type_id =
1270+ GetPointerType (context, referenced_type_expr.inst_id );
1271+ pointer_type_id =
1272+ GetConstType (context, context.types ().GetInstId (pointer_type_id));
1273+ return TypeExpr::ForUnsugared (context, pointer_type_id);
12761274}
12771275
12781276// Maps a C++ type to a Carbon type. `type` should not be canonicalized because
@@ -1318,6 +1316,81 @@ static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type)
13181316 return mapped;
13191317}
13201318
1319+ namespace {
1320+ // Information about how to map a C++ parameter type into Carbon.
1321+ struct ParameterTypeInfo {
1322+ // The type to use for the Carbon parameter.
1323+ TypeExpr type;
1324+ // Whether to build an `addr` pattern.
1325+ bool want_addr_pattern;
1326+ // If building an `addr` pattern, the type matched by that pattern.
1327+ TypeExpr pointee_type;
1328+ };
1329+ } // namespace
1330+
1331+ // Given the type of a C++ function parameter, returns information about the
1332+ // type to use for the corresponding Carbon parameter.
1333+ //
1334+ // Note that if the parameter has a type for which `IsSimpleAbiType` returns
1335+ // true, we must produce a parameter type that has the same calling convention
1336+ // as the C++ type.
1337+ //
1338+ // TODO: Use `ref` instead of `addr`.
1339+ static auto MapParameterType (Context& context, SemIR::LocId loc_id,
1340+ clang::QualType param_type) -> ParameterTypeInfo {
1341+ ParameterTypeInfo info = {.type = TypeExpr::None,
1342+ .want_addr_pattern = false ,
1343+ .pointee_type = TypeExpr::None};
1344+
1345+ // Perform some custom mapping for parameters of reference type:
1346+ //
1347+ // * `T& x` -> `addr x: T*`.
1348+ // * `const T& x` -> `x: T`.
1349+ // * `T&& x` -> `x: T`.
1350+ //
1351+ // TODO: For the `&&` mapping, we allow an rvalue reference to bind to a
1352+ // durable reference expression. This should not be allowed.
1353+ if (param_type->isReferenceType ()) {
1354+ clang::QualType pointee_type = param_type->getPointeeType ();
1355+ if (param_type->isLValueReferenceType ()) {
1356+ if (pointee_type.isConstQualified ()) {
1357+ // TODO: Consider only doing this if `const` is the only qualifier. For
1358+ // now, any other qualifier will fail when mapping the type.
1359+ auto split_type = pointee_type.getSplitUnqualifiedType ();
1360+ split_type.Quals .removeConst ();
1361+ pointee_type = context.ast_context ().getQualifiedType (split_type);
1362+ } else {
1363+ // The reference will map to a pointer. Request an `addr` pattern.
1364+ info.want_addr_pattern = true ;
1365+ }
1366+ }
1367+ param_type = pointee_type;
1368+ }
1369+
1370+ info.type = MapType (context, loc_id, param_type);
1371+ if (info.want_addr_pattern && info.type .inst_id .has_value ()) {
1372+ info.pointee_type = info.type ;
1373+ info.type = TypeExpr::ForUnsugared (
1374+ context, GetPointerType (context, info.pointee_type .inst_id ));
1375+ }
1376+ return info;
1377+ }
1378+
1379+ // Finishes building the pattern to use for a function parameter, given the
1380+ // binding pattern and information about how the parameter is being mapped into
1381+ // Carbon.
1382+ static auto FinishParameterPattern (Context& context, SemIR::InstId pattern_id,
1383+ ParameterTypeInfo info) -> SemIR::InstId {
1384+ if (!info.want_addr_pattern || pattern_id == SemIR::ErrorInst::InstId) {
1385+ return pattern_id;
1386+ }
1387+ return AddPatternInst (
1388+ context, {SemIR::LocId (pattern_id),
1389+ SemIR::AddrPattern ({.type_id = GetPatternType (
1390+ context, info.pointee_type .type_id ),
1391+ .inner_id = pattern_id})});
1392+ }
1393+
13211394// Returns a block for the implicit parameters of the given function
13221395// declaration. Because function templates are not yet supported, this currently
13231396// only contains the `self` parameter. On error, produces a diagnostic and
@@ -1334,32 +1407,10 @@ static auto MakeImplicitParamPatternsBlockId(
13341407 // Build a `self` parameter from the object parameter.
13351408 BeginSubpattern (context);
13361409
1337- // Perform some special-case mapping for the object parameter:
1338- //
1339- // - If it's a const reference to T, produce a by-value `self: T` parameter.
1340- // - If it's a non-const reference to T, produce an `addr self: T*`
1341- // parameter.
1342- // - Otherwise, map it directly, which will currently fail for `&&`-qualified
1343- // methods.
1344- //
1345- // TODO: Some of this mapping should be performed for all parameters.
13461410 clang::QualType param_type =
13471411 method_decl->getFunctionObjectParameterReferenceType ();
1348- bool addr_self = false ;
1349- if (param_type->isLValueReferenceType ()) {
1350- param_type = param_type.getNonReferenceType ();
1351- if (param_type.isConstQualified ()) {
1352- // TODO: Consider only doing this if `const` is the only qualifier. For
1353- // now, any other qualifier will fail when mapping the type.
1354- auto split_type = param_type.getSplitUnqualifiedType ();
1355- split_type.Quals .removeConst ();
1356- param_type = method_decl->getASTContext ().getQualifiedType (split_type);
1357- } else {
1358- addr_self = true ;
1359- }
1360- }
1361-
1362- auto [type_inst_id, type_id] = MapType (context, loc_id, param_type);
1412+ auto param_info = MapParameterType (context, loc_id, param_type);
1413+ auto [type_inst_id, type_id] = param_info.type ;
13631414 SemIR::ExprRegionId type_expr_region_id =
13641415 EndSubpatternAsExpr (context, type_inst_id);
13651416
@@ -1372,10 +1423,8 @@ static auto MakeImplicitParamPatternsBlockId(
13721423
13731424 // TODO: Fill in a location once available.
13741425 auto pattern_id =
1375- addr_self ? AddAddrSelfParamPattern (context, SemIR::LocId::None,
1376- type_expr_region_id, type_inst_id)
1377- : AddSelfParamPattern (context, SemIR::LocId::None,
1378- type_expr_region_id, type_id);
1426+ AddSelfParamPattern (context, loc_id, type_expr_region_id, type_id);
1427+ pattern_id = FinishParameterPattern (context, pattern_id, param_info);
13791428
13801429 return context.inst_blocks ().Add ({pattern_id});
13811430}
@@ -1409,12 +1458,11 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
14091458 // TODO: The presence of qualifiers here is probably a Clang bug.
14101459 clang::QualType param_type = orig_param_type.getUnqualifiedType ();
14111460
1412- bool is_ref_param = param_type->isLValueReferenceType ();
1413-
14141461 // Mark the start of a region of insts, needed for the type expression
14151462 // created later with the call of `EndSubpatternAsExpr()`.
14161463 BeginSubpattern (context);
1417- auto [orig_type_inst_id, type_id] = MapType (context, loc_id, param_type);
1464+ auto param_info = MapParameterType (context, loc_id, param_type);
1465+ auto [orig_type_inst_id, type_id] = param_info.type ;
14181466 // Type expression of the binding pattern - a single-entry/single-exit
14191467 // region that allows control flow in the type expression e.g. fn F(x: if C
14201468 // then i32 else i64).
@@ -1452,17 +1500,7 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
14521500 {.type_id = context.insts ().Get (pattern_id).type_id (),
14531501 .subpattern_id = pattern_id,
14541502 .index = SemIR::CallParamIndex::None})});
1455- if (is_ref_param) {
1456- // We map `T&` parameters to `addr param: T*`.
1457- // TODO: Revisit this and decide what we really want to do here.
1458- pattern_id = AddPatternInst (
1459- context, {param_loc_id,
1460- SemIR::AddrPattern (
1461- {.type_id = GetPatternType (
1462- context, context.types ().GetTypeIdForTypeInstId (
1463- orig_type_inst_id)),
1464- .inner_id = pattern_id})});
1465- }
1503+ pattern_id = FinishParameterPattern (context, pattern_id, param_info);
14661504 params.push_back (pattern_id);
14671505 }
14681506 return context.inst_blocks ().Add (params);
@@ -1476,6 +1514,9 @@ static auto GetReturnTypeExpr(Context& context, SemIR::LocId loc_id,
14761514 clang::FunctionDecl* clang_decl) -> TypeExpr {
14771515 clang::QualType orig_ret_type = clang_decl->getReturnType ();
14781516 if (!orig_ret_type->isVoidType ()) {
1517+ // TODO: We should eventually map reference returns to non-pointer types
1518+ // here. We should return by `ref` for `T&` return types once `ref` return
1519+ // is implemented.
14791520 auto [orig_type_inst_id, type_id] = MapType (context, loc_id, orig_ret_type);
14801521 if (!orig_type_inst_id.has_value ()) {
14811522 context.TODO (loc_id, llvm::formatv (" Unsupported: return type: {0}" ,
0 commit comments