@@ -50,106 +50,30 @@ static auto GenerateThunkMangledName(
5050  return  mangled_name_stream.TakeStr ();
5151}
5252
53- //  Returns true if a C++ thunk is required for the given type. A C++ thunk is
54- //  required for any type except for void, pointer types and signed 32-bit and
55- //  64-bit integers.
56- static  auto  IsThunkRequiredForType (Context& context, SemIR::TypeId type_id)
57-     -> bool {
58-   if  (!type_id.has_value () || type_id == SemIR::ErrorInst::TypeId) {
59-     return  false ;
60-   }
61- 
62-   type_id = context.types ().GetUnqualifiedType (type_id);
63- 
64-   switch  (context.types ().GetAsInst (type_id).kind ()) {
65-     case  SemIR::PointerType::Kind: {
66-       return  false ;
67-     }
68- 
69-     case  SemIR::ClassType::Kind: {
70-       if  (!context.types ().IsComplete (type_id)) {
71-         //  Signed integers of 32 or 64 bits should be completed when imported.
72-         return  true ;
73-       }
74- 
75-       auto  int_info = context.types ().TryGetIntTypeInfo (type_id);
76-       if  (!int_info || !int_info->bit_width .has_value ()) {
77-         return  true ;
78-       }
79- 
80-       llvm::APInt bit_width = context.ints ().Get (int_info->bit_width );
81-       return  bit_width != 32  && bit_width != 64 ;
82-     }
83- 
84-     default :
85-       return  true ;
86-   }
87- }
88- 
89- auto  IsCppThunkRequired (Context& context, const  SemIR::Function& function)
90-     -> bool {
91-   if  (!function.clang_decl_id .has_value ()) {
92-     return  false ;
93-   }
94- 
95-   //  A thunk is required if any parameter or return type requires it. However,
96-   //  we don't generate a thunk if any relevant type is erroneous.
97-   bool  thunk_required = false ;
98- 
99-   const  auto & decl_info = context.clang_decls ().Get (function.clang_decl_id );
100-   const  auto * decl = cast<clang::FunctionDecl>(decl_info.key .decl );
101-   if  (decl_info.key .num_params  !=
102-       static_cast <int >(decl->getNumNonObjectParams ())) {
103-     //  We require a thunk if the number of parameters we want isn't all of them.
104-     //  This happens if default arguments are in use, or (eventually) when
105-     //  calling a varargs function.
106-     thunk_required = true ;
107-   } else  {
108-     //  We require a thunk if any parameter is of reference type, even if the
109-     //  corresponding SemIR function has an acceptable parameter type.
110-     //  TODO: We should be able to avoid thunks for reference parameters.
111-     for  (auto * param : decl->parameters ()) {
112-       if  (param->getType ()->isReferenceType ()) {
113-         thunk_required = true ;
114-         break ;
115-       }
116-     }
53+ //  Returns whether the Carbon lowering for a parameter or return of this type is
54+ //  known to match the C++ lowering.
55+ static  auto  IsSimpleAbiType (clang::ASTContext& ast_context,
56+                             clang::QualType type, bool  for_parameter) -> bool {
57+   if  (type->isVoidType () || type->isPointerType ()) {
58+     return  true ;
11759  }
11860
119-   SemIR::TypeId return_type_id =
120-       function.GetDeclaredReturnType (context.sem_ir ());
121-   if  (return_type_id.has_value ()) {
122-     if  (return_type_id == SemIR::ErrorInst::TypeId) {
123-       return  false ;
124-     }
125-     thunk_required =
126-         thunk_required || IsThunkRequiredForType (context, return_type_id);
61+   if  (!for_parameter && type->isLValueReferenceType ()) {
62+     //  An lvalue reference return type maps to a pointer, which uses the same
63+     //  lowering rule.
64+     return  true ;
12765  }
12866
129-   for  (auto  param_id :
130-        context.inst_blocks ().GetOrEmpty (function.call_params_id )) {
131-     if  (param_id == SemIR::ErrorInst::InstId) {
67+   if  (const  auto * enum_decl = type->getAsEnumDecl ()) {
68+     //  An enum type has a simple ABI if its underlying type does.
69+     type = enum_decl->getIntegerType ();
70+     if  (type.isNull ()) {
13271      return  false ;
13372    }
134-     thunk_required =
135-         thunk_required ||
136-         IsThunkRequiredForType (
137-             context, context.insts ().GetAs <SemIR::AnyParam>(param_id).type_id );
138-   }
139- 
140-   return  thunk_required;
141- }
142- 
143- //  Returns whether the type is void, a pointer, or a signed int of 32 or 64
144- //  bits.
145- static  auto  IsSimpleAbiType (clang::ASTContext& ast_context,
146-                             clang::QualType type) -> bool {
147-   if  (type->isVoidType () || type->isPointerType ()) {
148-     return  true ;
14973  }
15074
15175  if  (const  auto * builtin_type = type->getAs <clang::BuiltinType>()) {
152-     if  (builtin_type->isSignedInteger ()) {
76+     if  (builtin_type->isIntegerType ()) {
15377      uint64_t  type_size = ast_context.getIntWidth (type);
15478      return  type_size == 32  || type_size == 64 ;
15579    }
@@ -174,8 +98,8 @@ struct CalleeFunctionInfo {
17498    effective_return_type =
17599        is_ctor ? ast_context.getCanonicalTagType (method_decl->getParent ())
176100                : decl->getReturnType ();
177-     has_simple_return_type =
178-         IsSimpleAbiType (ast_context, effective_return_type );
101+     has_simple_return_type =  IsSimpleAbiType (ast_context, effective_return_type, 
102+                                               /* for_parameter= */ false );
179103  }
180104
181105  //  Returns whether this callee has an implicit `this` parameter.
@@ -234,6 +158,52 @@ struct CalleeFunctionInfo {
234158};
235159}  //  namespace
236160
161+ auto  IsCppThunkRequired (Context& context, const  SemIR::Function& function)
162+     -> bool {
163+   if  (!function.clang_decl_id .has_value ()) {
164+     return  false ;
165+   }
166+ 
167+   const  auto & decl_info = context.clang_decls ().Get (function.clang_decl_id );
168+   auto * decl = cast<clang::FunctionDecl>(decl_info.key .decl );
169+   if  (decl_info.key .num_params  !=
170+       static_cast <int >(decl->getNumNonObjectParams ())) {
171+     //  We require a thunk if the number of parameters we want isn't all of them.
172+     //  This happens if default arguments are in use, or (eventually) when
173+     //  calling a varargs function.
174+     return  true ;
175+   }
176+ 
177+   CalleeFunctionInfo callee_info (decl, decl_info.key .num_params );
178+   if  (!callee_info.has_simple_return_type ) {
179+     return  true ;
180+   }
181+ 
182+   auto & ast_context = context.ast_context ();
183+   if  (callee_info.has_implicit_object_parameter ()) {
184+     //  TODO: The object parameter is a reference parameter, but we don't force a
185+     //  thunk here like we do for explicit reference parameters in the case where
186+     //  we would map the parameter to an `addr` parameter. We should make this
187+     //  behavior consistent.
188+     auto * method_decl = cast<clang::CXXMethodDecl>(decl);
189+     if  (method_decl->getRefQualifier () == clang::RQ_RValue ||
190+         method_decl->getMethodQualifiers ().hasConst ()) {
191+       return  true ;
192+     }
193+   }
194+ 
195+   const  auto * function_type =
196+       decl->getType ()->castAs <clang::FunctionProtoType>();
197+   for  (int  i : llvm::seq (decl->getNumParams ())) {
198+     if  (!IsSimpleAbiType (ast_context, function_type->getParamType (i),
199+                          /* for_parameter=*/ true )) {
200+       return  true ;
201+     }
202+   }
203+ 
204+   return  false ;
205+ }
206+ 
237207//  Given a pointer type, returns the corresponding _Nonnull-qualified pointer
238208//  type.
239209static  auto  GetNonnullType (clang::ASTContext& ast_context,
@@ -255,7 +225,7 @@ static auto GetNonNullablePointerType(clang::ASTContext& ast_context,
255225static  auto  GetThunkParameterType (clang::ASTContext& ast_context,
256226                                  clang::QualType callee_type)
257227    -> clang::QualType {
258-   if  (IsSimpleAbiType (ast_context, callee_type)) {
228+   if  (IsSimpleAbiType (ast_context, callee_type,  /* for_parameter= */ true )) {
259229    return  callee_type;
260230  }
261231  return  GetNonNullablePointerType (ast_context, callee_type);
0 commit comments