llvm / llvm-project

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

[clang] [C++] Redefinition in hidden friend template #107861

Open PolarLinda6 opened 1 week ago

PolarLinda6 commented 1 week ago
template<typename>
void func();

template<typename>
struct define_func {
  template<typename>
  friend void func() {}
};

auto main() -> int {
  [[maybe_unused]] define_func<int> _{};
}

error message:

<source>:7:15: error: redefinition of 'func'
    7 |   friend void func() {}
      |               ^
<source>:11:37: note: in instantiation of template class 'define_func<int>' requested here
   11 |   [[maybe_unused]] define_func<int> _{};
      |                                     ^
<source>:7:15: note: previous definition is here
    7 |   friend void func() {}
      |               ^

Additional Information:

Version: clang version 18.1.8 Link: godbolt

PS: The code compiles successfully on gcc and msvc.

llvmbot commented 1 week ago

@llvm/issue-subscribers-clang-frontend

Author: PolarLinda6 (PolarLinda6)

```cpp template<typename> void func(); template<typename> struct define_func { template<typename> friend void func() {} }; auto main() -> int { [[maybe_unused]] define_func<int> _{}; } ``` #### error message: ```txt <source>:7:15: error: redefinition of 'func' 7 | friend void func() {} | ^ <source>:11:37: note: in instantiation of template class 'define_func<int>' requested here 11 | [[maybe_unused]] define_func<int> _{}; | ^ <source>:7:15: note: previous definition is here 7 | friend void func() {} | ^ ``` #### Additional Information: Version: clang version 18.1.8 Link: [godbolt](https://godbolt.org/z/xfM17vcMc) PS: The code compiles successfully on gcc and msvc.
zyn0217 commented 1 week ago

See also https://github.com/llvm/llvm-project/issues/7324. The code above is seemingly supposed to be ill-formed, and we reject it by design.

zyn0217 commented 1 week ago

And CWG2174 is also related.

PolarLinda6 commented 1 week ago

See also #7324. The code above is seemingly supposed to be ill-formed, and we reject it by design. See also #7324. The code above is seemingly supposed to be ill-formed, and we reject it by design.

The above define_func is indeed bad and unhealthy. However, I think it is incorrect to prompt for redefinition when there is only one definition.

When using non-function templates, the behavior is normal, see the following example, (I don't think function templates are any more special than non-function templates)

The following code compiles successfully

void func();

template<typename>
struct define_func {
  friend void func() {}
};

auto main() -> int {
  [[maybe_unused]] define_func<int> _{};
}

The following code failed to compile, indicating a redefinition

void func();

template<typename>
struct define_func {
  friend void func() {}
};

auto main() -> int {
  [[maybe_unused]] define_func<int> _{};
  [[maybe_unused]] define_func<double> __{};
}
zyn0217 commented 1 week ago

And interesting enough that, if we somehow referenced the template parameter in the friend declaration, then clang would accept it:

https://godbolt.org/z/Kjx7GKsqM

and clearly we reject the case from CWG2174:

https://godbolt.org/z/ETdY7Yzh4

@cor3ntin @erichkeane do you have any thoughts?