Commit Graph

6 Commits

Author SHA1 Message Date
Serge Pavlov acfcd78aec Diagnose friend function template redefinitions.
Friend function template defined in a class template becomes available if
the enclosing class template is instantiated. Until the function template
is used, it does not have a body, but still is considered a definition for
the purpose of redeclaration checks.

This change modifies redefinition check so that it can find the friend
function template definitions in instantiated classes.

Differential Revision: http://reviews.llvm.org/D21508

llvm-svn: 348473
2018-12-06 09:35:04 +00:00
Serge Pavlov e6e534ca22 Function definition may have uninstantiated body
Current implementation of `FunctionDecl::isDefined` does not take into
account redeclarations that do not have bodies, but the bodies can be
instantiated from corresponding templated definition. This behavior does
not allow to detect function redefinition in the cases where friend
functions is defined in class templates. For instance, the code:
```
    template<typename T> struct X { friend void f() {} };
    X<int> xi;
    void f() {}
```
compiles successfully but must fail due to redefinition of `f`. The
declaration of the friend `f` is created when the containing template
`X` is instantiated, but it does not have a body as per 14.5.4p4
because `f` is not odr-used.

With this change the function `Sema::CheckForFunctionRedefinition`
considers functions with uninstantiated bodies as definitions.

Differential Revision: https://reviews.llvm.org/D30170

llvm-svn: 326419
2018-03-01 07:04:11 +00:00
Serge Pavlov 25dbe1a16e Function with unparsed body is a definition
While a function body is being parsed, the function declaration is not considered
as a definition because it does not have a body yet. In some cases it leads to
incorrect interpretation, the case is presented in
https://bugs.llvm.org/show_bug.cgi?id=14785:
```
    template<typename T> struct Somewhat {
      void internal() const {}
      friend void operator+(int const &, Somewhat<T> const &) {}
    };
void operator+(int const &, Somewhat<char> const &x) { x.internal(); }
```
When statement `x.internal()` in the body of global `operator+` is parsed, the type
of `x` must be completed, so the instantiation of `Somewhat<char>` is started. It
instantiates the declaration of `operator+` defined inline, and makes a check for
redefinition. The check does not detect another definition because the declaration
of `operator+` is still not defining as does not have a body yet.

To solves this problem the function `isThisDeclarationADefinition` considers
a function declaration as a definition if it has flag `WillHaveBody` set.

This change fixes PR14785.

Differential Revision: https://reviews.llvm.org/D30375

This is a recommit of 305379, reverted in 305381, with small changes.

llvm-svn: 305903
2017-06-21 12:46:57 +00:00
Serge Pavlov a4ab1b1c59 Reverted 305379 (Function with unparsed body is a definition)
It broke clang-x86_64-linux-selfhost-modules-2 and some other buildbots.

llvm-svn: 305381
2017-06-14 10:57:56 +00:00
Serge Pavlov c73c81be5c Function with unparsed body is a definition
While a function body is being parsed, the function declaration is not considered
as a definition because it does not have a body yet. In some cases it leads to
incorrect interpretation, the case is presented in
https://bugs.llvm.org/show_bug.cgi?id=14785:
```
    template<typename T> struct Somewhat {
      void internal() const {}
      friend void operator+(int const &, Somewhat<T> const &) {}
    };
void operator+(int const &, Somewhat<char> const &x) { x.internal(); }
```
When statement `x.internal()` in the body of global `operator+` is parsed, the type
of `x` must be completed, so the instantiation of `Somewhat<char>` is started. It
instantiates the declaration of `operator+` defined inline, and makes a check for
redefinition. The check does not detect another definition because the declaration
of `operator+` is still not defining as does not have a body yet.

To solves this problem the function `isThisDeclarationADefinition` considers
a function declaration as a definition if it has flag `WillHaveBody` set.

This change fixes PR14785.

Differential Revision: https://reviews.llvm.org/D30375

llvm-svn: 305379
2017-06-14 10:07:02 +00:00
Serge Pavlov 06b7a87298 Do not find friend function definitions inside non-instantiated class.
Previously if a file-level function was defined inside befriending
template class, it always was treated as defined. For instance, the code like:
```
  int func(int x);
  template<typename T> class C1 {
    friend int func(int x) { return x; }
  };
  template<typename T> class C2 {
    friend int func(int x) { return x; }
  };
```
could not be compiled due to function redefinition, although not of the templates
is instantiated. Moreover, the body of friend function can contain use of template
parameters, attempt to get definition of such function outside any instantiation
causes compiler abnormal termination.

Other compilers (gcc, icc) follow viewpoint that the body of the function defined
in friend declaration becomes available when corresponding class is instantiated.
This patch implements this viewpoint in clang.

Definitions introduced by friend declarations in template classes are not added
to the redeclaration chain of corresponding function. Only when the template is
instantiated, instantiation of the function definition is placed to the chain.

The fix was made in collaboration with Richard Smith.

This change fixes PR8035, PR17923, PR22307 and PR25848.

Differential Revision: http://reviews.llvm.org/D16989

llvm-svn: 283207
2016-10-04 10:11:43 +00:00