rjmccall added inline comments.

================
Comment at: clang/include/clang/AST/DeclCXX.h:1013
   CXXMethodDecl *getLambdaStaticInvoker() const;
+  CXXMethodDecl *getLambdaStaticInvoker(CallingConv CC) const;
+
----------------
Probably worth clarifying in the comment which invoker is returned by the 
no-arguments variant.


================
Comment at: clang/lib/AST/DeclCXX.cpp:1550
+                 return FTy->getCallConv() == CC;
+               });
+
----------------
This seems both rather more complicated and rather more expensive than a simple 
loop which assigns to a local pointer.


================
Comment at: clang/lib/AST/DeclCXX.cpp:1568
+    return llvm::find_if(Invokers, MDEqual) != Invokers.end();
+  }
+
----------------
Can you clarify how this method is semantically different from:

```
  assert(MD->getParent() == this);
  return isLambda() && MD->getName() == getLambdaStaticInvokerName();
```

other than probably inadvertently working with a method from a completely 
different class?


================
Comment at: clang/lib/AST/MicrosoftMangle.cpp:2268
+    } else if (const auto *AT = dyn_cast_or_null<AutoType>(
+                   ResultType->getContainedAutoType())) {
       Out << '?';
----------------
So, this is changing the mangling of lambda conversion operators.  Is this what 
MSVC does?


================
Comment at: clang/lib/Sema/SemaLambda.cpp:1467
+  llvm::SmallVector<CallingConv, 2> Conventions =
+      getLambdaConversionFunctionCallConv(S, CallOpProto);
+
----------------
Can we make this call a callback or something rather than returning an array 
that almost always has one element?


================
Comment at: clang/lib/Sema/SemaLambda.cpp:1278
+  if (CallOpCC == DefaultMember)
+    return DefaultFree;
+  return CallOpCC;
----------------
erichkeane wrote:
> rsmith wrote:
> > rsmith wrote:
> > > erichkeane wrote:
> > > > rjmccall wrote:
> > > > > ...I made this comment in my first review, but Phabricator threw it 
> > > > > away.
> > > > > 
> > > > > The attributes let you explicitly request the default method CC, 
> > > > > right?  I think you need to check for an explicit attribute rather 
> > > > > than just checking CC identity.  There should be an AttributedType in 
> > > > > the sugar.
> > > > They do, but I can't seem to find a way to find them.  The calling 
> > > > convention is already merged into the functiontype by the time we get 
> > > > here, the AttributedType isn't accessible.
> > > > 
> > > > So it seems we don't distinguish between "modified by attribute", 
> > > > "modified-default by command line", and "modified-default by 
> > > > TargetInfo."
> > > > 
> > > > That said, I somewhat think this is the right thing to do anyway.  If 
> > > > you're on a platform where the default call convention is different 
> > > > between a free-function and member-function, I'd think that this is 
> > > > what you MEAN...
> > > The `AttributedType` should be present in the type on the 
> > > `TypeSourceInfo` for the call operator. It might not be present on the 
> > > type retrieved by `getType()`, though.
> > > 
> > > Concretely, what targets have different calling conventions for member 
> > > versus non-member functions, and what do those calling conventions do 
> > > differently? (For example, if the default member calling convention 
> > > treats `this` differently, it doesn't seem reasonable to apply that to 
> > > the static invoker...)
> > Answering my own question: the only case where the default member calling 
> > convention is different from the default non-member calling convention is 
> > for MinGW on 32-bit x86, where members use `thiscall` by default (which 
> > passes the first parameter in `%ecx`).
> > 
> > Is it reasonable for `[] [[clang::thiscall]] {}` to result in a static 
> > invoker using the `thiscall` calling convention? Intuitively I'd say no, 
> > but there's not really anything specific to member functions in `thiscall` 
> > -- it just means that we pass the first argument in a register. (However, 
> > the first argument of the lambda and the first argument of its static 
> > invoker are different, so it's still somewhat unclear whether inheriting 
> > `thiscall` is appropriate. But usually for any given lambda only one of the 
> > two is actually used.)
> > 
> > But there's another quirk here: the default non-member calling convention 
> > can be set on the command line with `-fdefault-calling-conv=` (and a few 
> > other flags such as `-mrtd`). This doesn't affect member functions by 
> > default. So what should happen if this is compiled with 
> > `-fdefault-calling-conv=stdcall` (assuming the default calling convention 
> > is otherwise `cdecl`):
> > 
> > ```
> > auto *p0 = [] [[clang::stdcal]] {};
> > auto *p1 = [] {};
> > auto *p2 = [] [[clang::cdecl]] {};
> > ```
> > 
> > `p0` seems easy: the default non-member calling convention and the explicit 
> > calling convention are the same. The invoker should be `stdcall`.
> > 
> > For `p1`, the default member calling convention is `cdecl` but the default 
> > non-member calling convention is `stdcall`. In this case, conformance 
> > requires us to use `stdcall` for the pointer type, because `p1` is required 
> > to have type `void (*)()`, which is a `stdcall` function pointer in this 
> > configuration.
> > 
> > For `p2`, the call operator's calling convention has been explicitly set to 
> > the default member calling convention. I think in this case I'd expect a 
> > `cdecl` static invoker.
> > 
> > So I think I'm inclined to say we should always apply an explicit calling 
> > convention to both the call operator and the static invoker -- that seems 
> > like the simplest and easiest to explain rule, and probably matches user 
> > expectations most of the time, especially given the observation that you're 
> > usually writing a lambda only for one or the other of the call operator and 
> > the static invoker, so if you explicitly write a calling convention 
> > attribute, you presumably want it to apply to the part of the lambda's 
> > interface that you're using.
> > Answering my own question: the only case where the default member calling 
> > convention is different from the default non-member calling convention is 
> > for MinGW on 32-bit x86, where members use `thiscall` by default (which 
> > passes the first parameter in `%ecx`).
> > 
> > Is it reasonable for `[] [[clang::thiscall]] {}` to result in a static 
> > invoker using the `thiscall` calling convention? Intuitively I'd say no, 
> > but there's not really anything specific to member functions in `thiscall` 
> > -- it just means that we pass the first argument in a register. (However, 
> > the first argument of the lambda and the first argument of its static 
> > invoker are different, so it's still somewhat unclear whether inheriting 
> > `thiscall` is appropriate. But usually for any given lambda only one of the 
> > two is actually used.)
> > 
> > But there's another quirk here: the default non-member calling convention 
> > can be set on the command line with `-fdefault-calling-conv=` (and a few 
> > other flags such as `-mrtd`). This doesn't affect member functions by 
> > default. So what should happen if this is compiled with 
> > `-fdefault-calling-conv=stdcall` (assuming the default calling convention 
> > is otherwise `cdecl`):
> > 
> > ```
> > auto *p0 = [] [[clang::stdcal]] {};
> > auto *p1 = [] {};
> > auto *p2 = [] [[clang::cdecl]] {};
> > ```
> > 
> > `p0` seems easy: the default non-member calling convention and the explicit 
> > calling convention are the same. The invoker should be `stdcall`.
> > 
> > For `p1`, the default member calling convention is `cdecl` but the default 
> > non-member calling convention is `stdcall`. In this case, conformance 
> > requires us to use `stdcall` for the pointer type, because `p1` is required 
> > to have type `void (*)()`, which is a `stdcall` function pointer in this 
> > configuration.
> > 
> > For `p2`, the call operator's calling convention has been explicitly set to 
> > the default member calling convention. I think in this case I'd expect a 
> > `cdecl` static invoker.
> > 
> > So I think I'm inclined to say we should always apply an explicit calling 
> > convention to both the call operator and the static invoker -- that seems 
> > like the simplest and easiest to explain rule, and probably matches user 
> > expectations most of the time, especially given the observation that you're 
> > usually writing a lambda only for one or the other of the call operator and 
> > the static invoker, so if you explicitly write a calling convention 
> > attribute, you presumably want it to apply to the part of the lambda's 
> > interface that you're using.
> 
> Do we have a good way to determining which of the 3 mechanisms the user used 
> to set the calling convention?  (Attribute vs -fdefault-calling-conv= vs just 
> using the defualt?)
> 
> It would be easy enough to ALWAYS have the static-invoker match the 
> calling-convention of the operator(), as long as having it as a 'this' call 
> isn't a problem, which given what you said above, I don't think thats a 
> problem.  The implementation is trivial, since it is just removing the 
> condition above.
> 
> I guess I'm just asking which you'd like, and if it is the "only have invoker 
> match if user requested explicitly", if you had any hints on how to figure 
> that out.
> 
> Thanks!
I would guess that we probably have an AttributedType if and only if the user 
wrote an attribute explicitly, but I don't know for sure if we make one in the 
case where it's the only signature information in the lambda.  I also don't 
know if it survives the type-rewrite that happens after return-type inference.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D89559/new/

https://reviews.llvm.org/D89559

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to