Skip to content

clang fails to find operator -> #104268

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ahatanak opened this issue Aug 14, 2024 · 7 comments · Fixed by #104458
Open

clang fails to find operator -> #104268

ahatanak opened this issue Aug 14, 2024 · 7 comments · Fixed by #104458
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" regression:19 Regression in 19 release

Comments

@ahatanak
Copy link
Collaborator

ahatanak commented Aug 14, 2024

struct D {
  template <typename T> void m() {}
};

template <typename T> struct S {
  void init() { (*this)->template m<T>(); };

  D *operator->();
};

clang rejects the code with the following error message:

<source>:6:35: error: no member named 'm' in 'S<T>'
    6 |   void init() { (*this)->template m<T>(); };

It looks like clang's behavior changed after 1595988ee6f9732e7ea79928af8a470ad5ef7dbe.

@ahatanak ahatanak added the clang:frontend Language frontend issues, e.g. anything involving "Sema" label Aug 14, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 14, 2024

@llvm/issue-subscribers-clang-frontend

Author: Akira Hatanaka (ahatanak)

``` struct D { template <typename T> void m() {} };

template <typename T> struct S {
void init() { (*this)->template m<T>(); };

D *operator->();
};


clang rejects the code with the following error message:

&lt;source&gt;:6:35: error: no member named 'm' in 'S&lt;T&gt;'
    6 |   void init() { (*this)-&gt;template m&lt;T&gt;(); };

It looks like clang's behavior changed after 1595988ee6f9732e7ea79928af8a470ad5ef7dbe.
</details>

@ahatanak
Copy link
Collaborator Author

@sdkrystian is this expected?

@sdkrystian
Copy link
Member

@ahatanak This is rather interesting... we accept this:

struct D {
  template <typename T = 0> void m() {}
};

template <typename T> struct S {
  void init() { (*this)->m(); };

  D *operator->();
};

... but we reject your provided example. I have some ideas as to what is going wrong... I'll investigate tomorrow.

@porglezomp porglezomp added the regression:19 Regression in 19 release label Aug 14, 2024
sdkrystian added a commit that referenced this issue Sep 9, 2024
… 'operator->' in the current instantiation (#104458)

Currently, clang erroneously rejects the following:
```
struct A
{
    template<typename T>
    void f();
};

template<typename T>
struct B
{
    void g()
    {
        (*this)->template f<int>(); // error: no member named 'f' in 'B<T>'
    }

    A* operator->();
};
```

This happens because `Sema::ActOnStartCXXMemberReference` does not adjust the `ObjectType` parameter when `ObjectType` is a dependent type (except when the type is a `PointerType` and the class member access is the `->` form). Since the (possibly adjusted) `ObjectType` parameter (`B<T>` in the above example) is passed to `Parser::ParseOptionalCXXScopeSpecifier`, we end up looking up `f` in `B` rather than `A`. 

This patch fixes the issue by identifying cases where the type of the object expression `T` is a dependent, non-pointer type and:
- `T` is the current instantiation and lookup for `operator->` finds a member of the current instantiation, or
- `T` has at least one dependent base case, and `operator->` is not found in the current instantiation

and using `ASTContext::DependentTy` as the type of the object expression when the optional _nested-name-specifier_ is parsed.

Fixes #104268.
llvmbot pushed a commit to llvmbot/llvm-project that referenced this issue Sep 9, 2024
… 'operator->' in the current instantiation (llvm#104458)

Currently, clang erroneously rejects the following:
```
struct A
{
    template<typename T>
    void f();
};

template<typename T>
struct B
{
    void g()
    {
        (*this)->template f<int>(); // error: no member named 'f' in 'B<T>'
    }

    A* operator->();
};
```

This happens because `Sema::ActOnStartCXXMemberReference` does not adjust the `ObjectType` parameter when `ObjectType` is a dependent type (except when the type is a `PointerType` and the class member access is the `->` form). Since the (possibly adjusted) `ObjectType` parameter (`B<T>` in the above example) is passed to `Parser::ParseOptionalCXXScopeSpecifier`, we end up looking up `f` in `B` rather than `A`.

This patch fixes the issue by identifying cases where the type of the object expression `T` is a dependent, non-pointer type and:
- `T` is the current instantiation and lookup for `operator->` finds a member of the current instantiation, or
- `T` has at least one dependent base case, and `operator->` is not found in the current instantiation

and using `ASTContext::DependentTy` as the type of the object expression when the optional _nested-name-specifier_ is parsed.

Fixes llvm#104268.

(cherry picked from commit 3cdb30e)
@h-vetinari
Copy link
Contributor

This should probably be reopened, given that 3681d85 reverted #104458

@zyn0217 zyn0217 reopened this Sep 13, 2024
@porglezomp
Copy link
Contributor

porglezomp commented Sep 23, 2024

I see the new PR is here: #109422

@cor3ntin
Copy link
Contributor

@sdkrystian this is still broken https://godbolt.org/z/z4hGqTxjE

@porglezomp
Copy link
Contributor

It looks like the follow-up PR was reverted again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" regression:19 Regression in 19 release
Projects
None yet
7 participants