This is an archive of the discontinued LLVM Phabricator instance.

[clang] Fix consteval operators in template contexts
ClosedPublic

Authored by Fznamznon on May 26 2023, 4:04 AM.

Details

Summary

Clang used to reject consteval operators if they're used inside a
template due to TreeTransform putting two different DeclRefExpr
expressions for the same reference of the same operator declaration into
ReferenceToConsteval set.
It seems there was an attempt to not rebuild the whole operator that
never succeeded, so this patch just removes this attempt and
problemating referencing of a DeclRefExpr that always ended up
discarded.

Fixes https://github.com/llvm/llvm-project/issues/62886

Diff Detail

Event Timeline

Fznamznon created this revision.May 26 2023, 4:04 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 26 2023, 4:04 AM
Fznamznon requested review of this revision.May 26 2023, 4:04 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 26 2023, 4:04 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
cor3ntin added inline comments.May 26 2023, 4:55 AM
clang/lib/Sema/TreeTransform.h
11965–11968

I don't understand why we would not need to transform the callee. do we do that elsewhere?

Fznamznon added inline comments.May 26 2023, 5:06 AM
clang/lib/Sema/TreeTransform.h
11965–11968

For example, the code above for call and subscript operators never transforms the callee.
This TransFormExpr call seems to be a no-op for overloaded operator call case, and the result never ends up in the resulting ast.

Like @cor3ntin I'm concerned about removing the transform call. I'm just as concerned that it caused no regressions...

If we have to transform the arguments, then this can be a dependent thing, which means the callee should be possible to be dependent, right? Thus needs to be transformed somewhere?

Fznamznon added a comment.EditedMay 31 2023, 4:13 AM

Like @cor3ntin I'm concerned about removing the transform call. I'm just as concerned that it caused no regressions...

If we have to transform the arguments, then this can be a dependent thing, which means the callee should be possible to be dependent, right? Thus needs to be transformed somewhere?

Oh, I didn't get @cor3ntin 's question in the first place! The question was where the callee instantiated, right? The callee is instantiated when the whole operator call expr is rebuilt in Sema::RebuildCXXOperatorCallExpr. From what I see, Sema::RebuildCXXOperatorCallExpr doesn't really care which callee is passed there. It checks which operation it represents and performs lookup depending on the arguments. This triggers instantiation.

Please see the test I'm adding. There is several cases where the operator callee is dependent. They work fine with the change. I also see the instantiated function decl in the AST, just the same as before the change.

rsmith added inline comments.May 31 2023, 12:37 PM
clang/lib/Sema/TreeTransform.h
11965–11968

To me it looks like we need to transform the callee in order to transform the declarations in the UnresolvedLookupExpr, if the operator has such functions. For example, in:

namespace A {
  template<typename T> T f(T t) {
    T operator+(T, T);
    return t + t;
  }
}
namespace B {
  struct X {};
}
void g(B::X x) { A::f(x); }

... we need to transform the UnresolvedLookupExpr for the t + t to map from the operator+ declaration in the A::f template to the instantiated operator+ declaration in A::f<B::X>.

But I think this patch is going in the right direction. We don't *actually* want to transform the callee; all we want to do is to transform the function or list of functions contained in the callee to form an UnresolvedSet of candidates found during the template parse. Building and then throwing away a DeclRefExpr or UnresolvedLookupExpr denoting that function or set of functions is both a waste of time and (as demonstrated by the bug being addressed here) problematic.

Instead of calling TransformExpr on the callee, we should be calling TransformOverloadExprDecls if the callee is an UnresolvedLookupExpr or TransformDecl if it's a DeclRefExpr, and I think RebuildCXXOperatorCallExpr should be changed to take an UnresolvedSet and a RequiresADL flag, and it looks like we can then remove the OrigCallee parameter, if we pass in some extra source locations.

Fznamznon added inline comments.Jun 1 2023, 10:47 AM
clang/lib/Sema/TreeTransform.h
11965–11968

Thank you for the feedback @rsmith , I appreciate it very much.
I tried the described approach, and it fixes the original bug I was trying to resolve as well as makes the mentioned example work correctly whereas my original change broke it. Apparently, we don't have test like that in check-clang set. I'm going to polish the resulting code a bit and put up to review tomorrow.

Fznamznon updated this revision to Diff 527808.Jun 2 2023, 4:31 AM

Transform the callee, add a test

libcxx CI seems to be failing for other patches as well.

cor3ntin added inline comments.Jun 6 2023, 6:26 AM
clang/lib/Sema/TreeTransform.h
12002

Can Functions ever held more than one element here?

Fznamznon added inline comments.Jun 6 2023, 6:44 AM
clang/lib/Sema/TreeTransform.h
12002

Good catch! I don't think that more than one element can happen here.

Fznamznon updated this revision to Diff 529220.Jun 7 2023, 2:14 AM

Use 1-element UnresolvedSet, rebase

cor3ntin added inline comments.Jun 7 2023, 2:25 AM
clang/lib/Sema/TreeTransform.h
11988–12014

I don't think this is useful, it is only used L11999 but not in L11994, and in either cases you can use ULE->requiresADL()

12015

here i think RequiresADL is always false

15213–15214

Maybe it would be worth investigating that further before merging the PR? Although the pr is a clear improvement so I'll let you decide what to do!

Fznamznon added inline comments.Jun 7 2023, 2:57 AM
clang/lib/Sema/TreeTransform.h
15213–15214

I've noticed that it is likely a dead code, so I didn't want to pass more parameters to RebuildCXXOperatorCallExpr in order to support dead code, but didn't feel confident enough to remove it. So I left this FIXME.
RebuildCXXOperatorCallExpr is only called by TransformCXXOperatorCallExpr and TransformCXXFoldExpr. When subscript expression comes to TransformCXXOperatorCallExpr, it never falls down to RebuildCXXOperatorCallExpr after c1512250960bd247519a9f959ad4af202402dcc4 , and I don't think that it is possible to have subscript expression as a part of a fold expression. So, for me, it seems the whole if and FIXME actually can be removed. WDYT?

Fznamznon updated this revision to Diff 529229.Jun 7 2023, 3:10 AM

Remove RequiresADL

cor3ntin added inline comments.Jun 7 2023, 4:04 AM
clang/lib/Sema/TreeTransform.h
15213–15214

I think you are right, It's seems like something I should have done as part of rGc1512250960bd247519a9f959ad4af202402dcc4.

It think you should remove it. (if we break something we can put it back with tests!)

Fznamznon updated this revision to Diff 529244.Jun 7 2023, 4:16 AM

Remove dead code

cor3ntin accepted this revision.Jun 7 2023, 4:18 AM

I think this looks good!
Thanks

This revision is now accepted and ready to land.Jun 7 2023, 4:18 AM
This revision was automatically updated to reflect the committed changes.