llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
27.9k stars 11.51k forks source link

Invalid private member diagnostic of template using with decltype of private member method #41693

Open llvmbot opened 5 years ago

llvmbot commented 5 years ago
Bugzilla Link 42348
Version trunk
OS All
Reporter LLVM Bugzilla Contributor
CC @DougGregor,@smilingthax,@zygoloid

Extended Description

The following code fails to compile with an erroneous error "'Impl' is a private member of 'S'":

  template <typename> struct S
    {
    private:
    template <typename> static constexpr auto Impl();

    public:
    template <typename X> using U = decltype(Impl<X>());
    };

  template <typename T> template <typename>
  constexpr auto S<T>::Impl() { }

  using X = S<void>::U<void>;

The above code compiles in gcc et al. Making the following change allows compilation:

  template <typename> struct S
    {
    private:
    struct W
      {
      template <typename> static constexpr auto Impl();
      };

    public:
    template <typename X> using U = decltype(W::template Impl<X>());
    };

  template <typename T> template <typename>
  constexpr auto S<T>::W::Impl()
    { }
llvmbot commented 5 years ago

The following is a more minimal version of the above showing the same error:

  struct S
    {
    private:
    template <typename> static constexpr void Impl() { }

    public:
    template <typename X> using U = decltype(Impl<X>());
    };

  using X = S::U<void>;
shafik commented 11 months ago

Confirmed: https://godbolt.org/z/76ncerc3T

see https://github.com/llvm/llvm-project/issues/66604 for some more examples

llvmbot commented 10 months ago

@llvm/issue-subscribers-clang-frontend

Author: None (llvmbot)

| | | | --- | --- | | Bugzilla Link | [42348](https://llvm.org/bz42348) | | Version | trunk | | OS | All | | Reporter | LLVM Bugzilla Contributor | | CC | @DougGregor,@smilingthax,@zygoloid | ## Extended Description The following code fails to compile with an erroneous error "'Impl' is a private member of 'S<void>'": ```cpp template <typename> struct S { private: template <typename> static constexpr auto Impl(); public: template <typename X> using U = decltype(Impl<X>()); }; template <typename T> template <typename> constexpr auto S<T>::Impl() { } using X = S<void>::U<void>; ``` The above code compiles in gcc et al. Making the following change allows compilation: ```cpp template <typename> struct S { private: struct W { template <typename> static constexpr auto Impl(); }; public: template <typename X> using U = decltype(W::template Impl<X>()); }; template <typename T> template <typename> constexpr auto S<T>::W::Impl() { } ```
Fznamznon commented 9 months ago

Patch was reverted so reopening this one.

EugeneZelenko commented 9 months ago

Fix was done in private branch.

Fznamznon commented 9 months ago

Ok, I've made two attempts to fix but both ended up insufficient. The idea was simple - since access checks depend on context:

https://github.com/llvm/llvm-project/blob/2103de0c4cced5d06165a8a8a84cec89c8ab3be0/clang/lib/Sema/SemaAccess.cpp#L1483

, let's start instantiation of a type alias from the context where the alias is declared. This fixes the problem from this issue. However, there is also this piece of code starting from:

https://github.com/llvm/llvm-project/blob/f32662a40b0cc25f779ed10ea6515ba798922df8/clang/lib/Sema/SemaTemplate.cpp#L4054

that checks if some type referenced ATM with a template-id matches current context (or outer context) and this context is a record, then canonical type of the type that is being checked is assigned with InjectedClassNameType of the found record. And it seems there might be quite a lot of uncovered by check-clang tests cases where switch of the CurContext breaks this whole scheme. I worked around at least two cases in https://github.com/llvm/llvm-project/pull/75069, and received two other reported. So, perhaps there should be another, less obvious approach to fix this.

cc @zygoloid , @cor3ntin , @erichkeane in case you have other ideas.

EugeneZelenko commented 8 months ago

Not merged yet.

llvmbot commented 8 months ago

@llvm/issue-subscribers-c-11

Author: None (llvmbot)

| | | | --- | --- | | Bugzilla Link | [42348](https://llvm.org/bz42348) | | Version | trunk | | OS | All | | Reporter | LLVM Bugzilla Contributor | | CC | @DougGregor,@smilingthax,@zygoloid | ## Extended Description The following code fails to compile with an erroneous error "'Impl' is a private member of 'S<void>'": ```cpp template <typename> struct S { private: template <typename> static constexpr auto Impl(); public: template <typename X> using U = decltype(Impl<X>()); }; template <typename T> template <typename> constexpr auto S<T>::Impl() { } using X = S<void>::U<void>; ``` The above code compiles in gcc et al. Making the following change allows compilation: ```cpp template <typename> struct S { private: struct W { template <typename> static constexpr auto Impl(); }; public: template <typename X> using U = decltype(W::template Impl<X>()); }; template <typename T> template <typename> constexpr auto S<T>::W::Impl() { } ```