================
@@ -5493,23 +5520,25 @@ TypeSourceInfo 
*TemplateDeclInstantiator::SubstFunctionType(
       // the function parameters themselves.
       const FunctionProtoType *OldProto =
           cast<FunctionProtoType>(OldProtoLoc.getType());
-      for (unsigned i = 0, i_end = OldProtoLoc.getNumParams(); i != i_end;
-           ++i) {
-        ParmVarDecl *OldParam = OldProtoLoc.getParam(i);
-        if (!OldParam) {
-          Params.push_back(SemaRef.BuildParmVarDeclForTypedef(
-              D, D->getLocation(), OldProto->getParamType(i)));
-          continue;
-        }
-
-        ParmVarDecl *Parm = SemaRef.SubstParmVarDecl(
-            OldParam, TemplateArgs, /*indexAdjustment=*/0,
-            /*NumExpansions=*/std::nullopt,
-            /*ExpectParameterPack=*/false, EvaluateConstraints);
-        if (!Parm)
-          return nullptr;
-        Params.push_back(Parm);
-      }
+      SmallVector<QualType, 4> ParamTypes;
+      Sema::ExtParameterInfoBuilder ExtParamInfos;
+      if (SemaRef.SubstParmTypes(D->getLocation(), OldProtoLoc.getParams(),
+                                 nullptr, TemplateArgs, ParamTypes, &Params,
+                                 ExtParamInfos, OldProto->param_type_begin(),
+                                 EvaluateConstraints))
+        return nullptr;
+      // Declare a parameter that was only a type in the prototype. A function
+      // declared through a typedef with an attribute that rewrites the
+      // function type in place, such as noreturn, gets a prototype whose
+      // parameters have no ParmVarDecl, so no attribute of the typedef's
+      // parameters reaches it; see TypeSpecLocFiller in SemaType.
+      // FIXME: Keep the typedef's parameters there instead. The dependent
+      // branch above returns null for such a prototype, dropping the member.
----------------
aaronpuchert wrote:

> Two families of function-type attributes. handleFunctionTypeAttr in 
> clang/lib/Sema/SemaType.cpp applies calling conventions and 
> ns_returns_retained by wrapping the written type in an AttributedType, so the 
> typedef sugar survives as the modified type and the type location still 
> mirrors the declarator.

I wonder whether that's related to the fact that calling conventions also 
survive canonicalization, unlike most static analysis attributes. Types have to 
be canonicalized for example when it comes to deciding which overloads are the 
same, or which template instantiations are the same.

```c++
void f(int (*)()) {}
void f(int (*)() [[gnu::ms_abi]]) {} // Ok.
void f(int (* _Nullable)()) {}       // error: redefinition
```

We don't want behavioral changes relative to a compiler that doesn't understand 
the attributes. (Unlike calling conventions, which change the ABI, static 
analysis attributes are just an add-on.) So they shouldn't affect overloading 
etc., decisions about that have be the independent of the attributes.

https://github.com/llvm/llvm-project/pull/232784
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to