[PATCH] D16579: Warn if friend function depends on template parameters.

2017-07-10 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 105853.
sepavloff added a comment.

Updated patch

- Remove changes that are not needed anymore,
- Function matching is implemented on recursive function instead of 
TypeVisitor. It support subset of checks, which should be enough for practical 
use.
- Added more comments.


https://reviews.llvm.org/D16579

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/Sema.cpp
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaDecl.cpp
  test/CXX/drs/dr3xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/CXX/temp/temp.res/p3.cpp
  test/SemaCXX/friend.cpp
  test/SemaCXX/overload-call.cpp

Index: test/SemaCXX/overload-call.cpp
===
--- test/SemaCXX/overload-call.cpp
+++ test/SemaCXX/overload-call.cpp
@@ -574,13 +574,17 @@
   // Ensure that overload resolution attempts to complete argument types when
   // performing ADL.
   template struct S {
-friend int f(const S&);
+friend int f(const S&);  // expected-warning{{friend declaration 'IncompleteArg::f' depends on template parameter but is not a function template}}
+ // expected-note@-1{{declare function outside class template to suppress this warning}}
+ // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
   };
   extern S s;
   int k = f(s);
 
   template struct Op {
-friend bool operator==(const Op &, const Op &);
+friend bool operator==(const Op &, const Op &);  // expected-warning{{friend declaration 'IncompleteArg::operator==' depends on template parameter but is not a function template}}
+ // expected-note@-1{{declare function outside class template to suppress this warning}}
+ // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
   };
   extern Op op;
   bool b = op == op;
Index: test/SemaCXX/friend.cpp
===
--- test/SemaCXX/friend.cpp
+++ test/SemaCXX/friend.cpp
@@ -388,3 +388,116 @@
 friend void f(void *p = 0) {} // expected-error {{must be the only}}
   };
 }
+
+template void pr23342_func(T x);
+template
+struct pr23342_C1 {
+  friend void pr23342_func<>(T x);
+  friend bool func(T x);  // expected-warning{{friend declaration 'func' depends on template parameter but is not a function template}}
+  // expected-note@-1{{declare function outside class template to suppress this warning}}
+  // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
+  friend bool func2(int x);
+  template friend bool func3(T2 x);
+  friend T func4();  // expected-warning{{friend declaration 'func4' depends on template parameter but is not a function template}}
+ // expected-note@-1{{declare function outside class template to suppress this warning}}
+ // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
+};
+
+namespace pr23342 {
+
+template
+struct C1 {
+  friend void pr23342_func<>(T x);
+  friend bool func(T x);  // expected-warning{{friend declaration 'pr23342::func' depends on template parameter but is not a function template}}
+  // expected-note@-1{{declare function outside class template to suppress this warning}}
+  // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
+  friend bool func2(int x);
+  template friend bool func3(T2 x);
+  friend T func4();// expected-warning{{friend declaration 'pr23342::func4' depends on template parameter but is not a function template}}
+   // expected-note@-1{{declare function outside class template to suppress this warning}}
+   // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
+};
+
+template 
+struct Arg {
+  friend bool operator==(const Arg& lhs, T rhs) {
+   return false;
+  }
+  friend bool operator!=(const Arg& lhs, T rhs);  // expected-warning{{friend declaration 'pr23342::operator!=' depends on template parameter but is not a function template}}
+   // expected-note@-1{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
+};
+template 
+bool operator!=(const Arg& lhs, T rhs) {
+  return true;
+}
+bool foo() {
+  Arg arg;
+  return (arg == 42) || (arg != 42);
+}
+
+
+template class C0 {
+  friend void func0(C0 &);  // expected-warning{{friend declaration 

Re: [PATCH] D16579: Warn if friend function depends on template parameters.

2016-07-09 Thread Serge Pavlov via cfe-commits
sepavloff marked 6 inline comments as done.


Comment at: include/clang/Sema/Sema.h:9469
@@ +9468,3 @@
+  /// of proper templates, but they are needed for checks.
+  SmallVector FriendsOfTemplates;
+

Do we really need it? When compiler is compiling a module containing enclosing 
class, it must emit these warning, as it does for separate file. The advice it 
issues is valid in this case also. When compiler compiles code that uses the 
module, warning is not needed as it must already been issued. So, it looks like 
serializing this array is not needed.


Comment at: lib/Sema/SemaChecking.cpp:10936
@@ +10935,3 @@
+/// function types.
+/*
+class FunctionMatcher : public TypeMatcher {

The visitor class is split into two auxiliary classes. Although amount of code 
becomes larger, maintainability should be better, as large amount of code is 
obtained from RecursiveASTVisitor in standard way/ the other is not specific to 
friend functions.


http://reviews.llvm.org/D16579



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D16579: Warn if friend function depends on template parameters.

2016-07-09 Thread Serge Pavlov via cfe-commits
sepavloff updated this revision to Diff 63387.
sepavloff added a comment.

Repared file modes.


http://reviews.llvm.org/D16579

Files:
  include/clang/AST/TypeInstantiationMatcher.h
  include/clang/AST/TypeMatcher.h
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/Sema.cpp
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaTemplate.cpp
  test/CXX/drs/dr3xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/SemaCXX/friend.cpp
  test/SemaCXX/overload-call.cpp

Index: test/SemaCXX/overload-call.cpp
===
--- test/SemaCXX/overload-call.cpp
+++ test/SemaCXX/overload-call.cpp
@@ -574,13 +574,17 @@
   // Ensure that overload resolution attempts to complete argument types when
   // performing ADL.
   template struct S {
-friend int f(const S&);
+friend int f(const S&);  // expected-warning{{friend declaration 'IncompleteArg::f' depends on template parameter but is not a function template}}
+ // expected-note@-1{{declare function outside class template to suppress this warning}}
+ // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
   };
   extern S s;
   int k = f(s);
 
   template struct Op {
-friend bool operator==(const Op &, const Op &);
+friend bool operator==(const Op &, const Op &);  // expected-warning{{friend declaration 'IncompleteArg::operator==' depends on template parameter but is not a function template}}
+ // expected-note@-1{{declare function outside class template to suppress this warning}}
+ // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
   };
   extern Op op;
   bool b = op == op;
Index: test/SemaCXX/friend.cpp
===
--- test/SemaCXX/friend.cpp
+++ test/SemaCXX/friend.cpp
@@ -379,3 +379,111 @@
 X *q = p;
   }
 }
+
+
+template void pr23342_func(T x);
+template
+struct pr23342_C1 {
+  friend void pr23342_func<>(T x);
+  friend bool func(T x);  // expected-warning{{friend declaration 'func' depends on template parameter but is not a function template}}
+  // expected-note@-1{{declare function outside class template to suppress this warning}}
+  // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
+  friend bool func2(int x);
+  template friend bool func3(T2 x);
+  friend T func4();  // expected-warning{{friend declaration 'func4' depends on template parameter but is not a function template}}
+ // expected-note@-1{{declare function outside class template to suppress this warning}}
+ // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
+};
+
+namespace pr23342 {
+
+template
+struct C1 {
+  friend void pr23342_func<>(T x);
+  friend bool func(T x);  // expected-warning{{friend declaration 'pr23342::func' depends on template parameter but is not a function template}}
+  // expected-note@-1{{declare function outside class template to suppress this warning}}
+  // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
+  friend bool func2(int x);
+  template friend bool func3(T2 x);
+  friend T func4();// expected-warning{{friend declaration 'pr23342::func4' depends on template parameter but is not a function template}}
+   // expected-note@-1{{declare function outside class template to suppress this warning}}
+   // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
+};
+
+template 
+struct Arg {
+  friend bool operator==(const Arg& lhs, T rhs) {
+   return false;
+  }
+  friend bool operator!=(const Arg& lhs, T rhs);  // expected-warning{{friend declaration 'pr23342::operator!=' depends on template parameter but is not a function template}}
+   // expected-note@-1{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
+};
+template 
+bool operator!=(const Arg& lhs, T rhs) {
+  return true;
+}
+bool foo() {
+  Arg arg;
+  return (arg == 42) || (arg != 42);
+}
+
+
+template class C0 {
+  friend void func0(C0 &);  // expected-warning{{friend declaration 'pr23342::func0' depends on template parameter but is not a function template}}
+   // expected-note@-1{{declare function outside class template 

Re: [PATCH] D16579: Warn if friend function depends on template parameters.

2016-07-09 Thread Serge Pavlov via cfe-commits
sepavloff updated this revision to Diff 63386.
sepavloff added a comment.

Updated patch


http://reviews.llvm.org/D16579

Files:
  include/clang/AST/TypeInstantiationMatcher.h
  include/clang/AST/TypeMatcher.h
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/Sema.cpp
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaTemplate.cpp
  test/CXX/drs/dr3xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/SemaCXX/friend.cpp
  test/SemaCXX/overload-call.cpp

Index: test/SemaCXX/overload-call.cpp
===
--- test/SemaCXX/overload-call.cpp
+++ test/SemaCXX/overload-call.cpp
@@ -574,13 +574,17 @@
   // Ensure that overload resolution attempts to complete argument types when
   // performing ADL.
   template struct S {
-friend int f(const S&);
+friend int f(const S&);  // expected-warning{{friend declaration 'IncompleteArg::f' depends on template parameter but is not a function template}}
+ // expected-note@-1{{declare function outside class template to suppress this warning}}
+ // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
   };
   extern S s;
   int k = f(s);
 
   template struct Op {
-friend bool operator==(const Op &, const Op &);
+friend bool operator==(const Op &, const Op &);  // expected-warning{{friend declaration 'IncompleteArg::operator==' depends on template parameter but is not a function template}}
+ // expected-note@-1{{declare function outside class template to suppress this warning}}
+ // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
   };
   extern Op op;
   bool b = op == op;
Index: test/SemaCXX/friend.cpp
===
--- test/SemaCXX/friend.cpp
+++ test/SemaCXX/friend.cpp
@@ -379,3 +379,111 @@
 X *q = p;
   }
 }
+
+
+template void pr23342_func(T x);
+template
+struct pr23342_C1 {
+  friend void pr23342_func<>(T x);
+  friend bool func(T x);  // expected-warning{{friend declaration 'func' depends on template parameter but is not a function template}}
+  // expected-note@-1{{declare function outside class template to suppress this warning}}
+  // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
+  friend bool func2(int x);
+  template friend bool func3(T2 x);
+  friend T func4();  // expected-warning{{friend declaration 'func4' depends on template parameter but is not a function template}}
+ // expected-note@-1{{declare function outside class template to suppress this warning}}
+ // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
+};
+
+namespace pr23342 {
+
+template
+struct C1 {
+  friend void pr23342_func<>(T x);
+  friend bool func(T x);  // expected-warning{{friend declaration 'pr23342::func' depends on template parameter but is not a function template}}
+  // expected-note@-1{{declare function outside class template to suppress this warning}}
+  // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
+  friend bool func2(int x);
+  template friend bool func3(T2 x);
+  friend T func4();// expected-warning{{friend declaration 'pr23342::func4' depends on template parameter but is not a function template}}
+   // expected-note@-1{{declare function outside class template to suppress this warning}}
+   // expected-note@-2{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
+};
+
+template 
+struct Arg {
+  friend bool operator==(const Arg& lhs, T rhs) {
+   return false;
+  }
+  friend bool operator!=(const Arg& lhs, T rhs);  // expected-warning{{friend declaration 'pr23342::operator!=' depends on template parameter but is not a function template}}
+   // expected-note@-1{{to befriend a template specialization, make sure the function template has already been declared and use '<>'}}
+};
+template 
+bool operator!=(const Arg& lhs, T rhs) {
+  return true;
+}
+bool foo() {
+  Arg arg;
+  return (arg == 42) || (arg != 42);
+}
+
+
+template class C0 {
+  friend void func0(C0 &);  // expected-warning{{friend declaration 'pr23342::func0' depends on template parameter but is not a function template}}
+   // expected-note@-1{{declare function outside class template to 

Re: [PATCH] D16579: Warn if friend function depends on template parameters.

2016-05-09 Thread Richard Smith via cfe-commits
rsmith added inline comments.


Comment at: include/clang/Basic/DiagnosticSemaKinds.td:1153
@@ +1152,3 @@
+def warn_non_template_friend : Warning<"friend declaration %q0 depends on "
+  "template parameter but is not a template function">,
+   InGroup;

template function -> function template


Comment at: include/clang/Basic/DiagnosticSemaKinds.td:1155-1157
@@ +1154,5 @@
+   InGroup;
+def note_non_template_friend : Note<"if this is intentional, add function "
+  "declaration to suppress the warning, if not - make sure the function "
+  "template has already been declared and use '<>'">;
+def note_befriend_template : Note<"to befriend a template specialization, "

Rather than this long conditional note, how about producing two notes here:

  note: declare function outside class template to suppress this warning
  note: use '<>' to befriend a template specialization


Comment at: include/clang/Basic/DiagnosticSemaKinds.td:1158-1159
@@ -1152,1 +1157,4 @@
+  "template has already been declared and use '<>'">;
+def note_befriend_template : Note<"to befriend a template specialization, "
+  "use '<>'">;
 

This note should also point out that you need to declare the function template 
prior to the class template.


Comment at: include/clang/Sema/Sema.h:9342
@@ +9341,3 @@
+  /// of proper templates, but they are needed for checks.
+  llvm::DenseSet FriendsOfTemplates;
+

This will produce diagnostics in a nondeterministic order, and you have no need 
of a set because there can never be any duplicates. Just use a `SmallVector`?


Comment at: include/clang/Sema/Sema.h:9342
@@ +9341,3 @@
+  /// of proper templates, but they are needed for checks.
+  llvm::DenseSet FriendsOfTemplates;
+

rsmith wrote:
> This will produce diagnostics in a nondeterministic order, and you have no 
> need of a set because there can never be any duplicates. Just use a 
> `SmallVector`?
You're missing serialization code for this for the PCH / preamble case.


Comment at: include/clang/Sema/Sema.h:9344-9345
@@ +9343,4 @@
+
+  /// \brief Check dependent friends functions for misinterpretation as 
template
+  /// ones.
+  void CheckDependentFriends();

friends -> friend
template ones -> function templates


Comment at: lib/Sema/SemaChecking.cpp:10468
@@ +10467,3 @@
+/// function types.
+class FunctionMatcher : public TypeVisitor {
+  const Type *InstType;

This is a huge amount of complexity and maintenance burden for this check, and 
it still seems to some important cases wrong. Is there a simpler way we can get 
a largely-equivalent result? Or maybe we can just unconditionally produce both 
notes?


Comment at: lib/Sema/SemaChecking.cpp:10700
@@ +10699,2 @@
+  }
+}

`FriendsOfTemplates.clear()` here?


Comment at: lib/Sema/SemaDecl.cpp:8502-8507
@@ -8501,1 +8501,8 @@
 
+  if (isFriend && !NewFD->isInvalidDecl()) {
+if (TemplateParamLists.empty() && !DC->isRecord() &&
+!isFunctionTemplateSpecialization) {
+  FriendsOfTemplates.insert(NewFD);
+}
+  }
+

This should also be conditioned on the function having a dependent type and 
this declaration not being a definition -- this will add all non-template 
friends to `FriendsOfTemplates`, whether they're friends of a class template or 
not.


http://reviews.llvm.org/D16579



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D16579: Warn if friend function depends on template parameters.

2016-05-09 Thread Serge Pavlov via cfe-commits
sepavloff updated this revision to Diff 56607.
sepavloff added a comment.

Changed implementation of friend function set.

Friend functions declared in template classes are not added to redeclaration 
chains,
but access to them is needed to make some checks. This change allows using the
set of friend functions not only to emit particular warning but also to serve 
as a
registry of file-level friend functions.


http://reviews.llvm.org/D16579

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/Sema.cpp
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaDecl.cpp
  test/CXX/drs/dr3xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/SemaCXX/friend.cpp
  test/SemaCXX/overload-call.cpp

Index: test/SemaCXX/overload-call.cpp
===
--- test/SemaCXX/overload-call.cpp
+++ test/SemaCXX/overload-call.cpp
@@ -574,13 +574,15 @@
   // Ensure that overload resolution attempts to complete argument types when
   // performing ADL.
   template struct S {
-friend int f(const S&);
+friend int f(const S&);  // expected-warning{{friend declaration 'IncompleteArg::f' depends on template parameter but is not a template function}}
+ // expected-note@-1{{if this is intentional, add function declaration to suppress the warning, if not - make sure the function template has already been declared and use '<>'}}
   };
   extern S s;
   int k = f(s);
 
   template struct Op {
-friend bool operator==(const Op &, const Op &);
+friend bool operator==(const Op &, const Op &);  // expected-warning{{friend declaration 'IncompleteArg::operator==' depends on template parameter but is not a template function}}
+ // expected-note@-1{{if this is intentional, add function declaration to suppress the warning, if not - make sure the function template has already been declared and use '<>'}}
   };
   extern Op op;
   bool b = op == op;
Index: test/SemaCXX/friend.cpp
===
--- test/SemaCXX/friend.cpp
+++ test/SemaCXX/friend.cpp
@@ -363,3 +363,102 @@
   f_pr6954(5); // expected-error{{undeclared identifier 'f_pr6954'}}
 }
 
+
+template void pr23342_func(T x);
+template
+struct pr23342_C1 {
+  friend void pr23342_func<>(T x);
+  friend bool func(T x);  // expected-warning{{friend declaration 'func' depends on template parameter but is not a template function}}
+  // expected-note@-1{{if this is intentional, add function declaration to suppress the warning, if not - make sure the function template has already been declared and use '<>'}}
+  friend bool func2(int x);
+  template friend bool func3(T2 x);
+  friend T func4();  // expected-warning{{friend declaration 'func4' depends on template parameter but is not a template function}}
+ // expected-note@-1{{if this is intentional, add function declaration to suppress the warning, if not - make sure the function template has already been declared and use '<>'}}
+};
+
+namespace pr23342 {
+
+template
+struct C1 {
+  friend void pr23342_func<>(T x);
+  friend bool func(T x);  // expected-warning{{friend declaration 'pr23342::func' depends on template parameter but is not a template function}}
+  // expected-note@-1{{if this is intentional, add function declaration to suppress the warning, if not - make sure the function template has already been declared and use '<>'}}
+  friend bool func2(int x);
+  template friend bool func3(T2 x);
+  friend T func4();// expected-warning{{friend declaration 'pr23342::func4' depends on template parameter but is not a template function}}
+   // expected-note@-1{{if this is intentional, add function declaration to suppress the warning, if not - make sure the function template has already been declared and use '<>'}}
+};
+
+template 
+struct Arg {
+  friend bool operator==(const Arg& lhs, T rhs) {
+   return false;
+  }
+  friend bool operator!=(const Arg& lhs, T rhs);  // expected-warning{{friend declaration 'pr23342::operator!=' depends on template parameter but is not a template function}}
+   // expected-note@-1{{to befriend a template specialization, use '<>'}}
+};
+template 
+bool operator!=(const Arg& lhs, T rhs) {
+  return true;
+}
+bool foo() {
+  Arg arg;
+  return (arg == 42) || (arg != 42);
+}
+
+
+template class C0 {
+  friend void func0(C0 &);  // expected-warning{{friend declaration 'pr23342::func0' depends on template parameter but is not a template function}}
+   // expected-note@-1{{if this is intentional, add function declaration to suppress the warning, if not - make sure the function template has already been declared and use '<>'}}
+};
+
+template class C0a {
+  friend void func0a(C0a &);  // expected-warning{{friend declaration 

Re: [PATCH] D16579: Warn if friend function depends on template parameters.

2016-04-04 Thread Serge Pavlov via cfe-commits
sepavloff updated this revision to Diff 52527.
sepavloff added a comment.

Updated patch

Added a check for presence of template declaration corresponding to the friend
function. Presence of similar functions but with specializations as argument
types is also checked now.

Made an atempt to make messages more clear to end user, not sure however if
they become better.


http://reviews.llvm.org/D16579

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/Sema.cpp
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaDecl.cpp
  test/CXX/drs/dr3xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/SemaCXX/friend.cpp
  test/SemaCXX/overload-call.cpp

Index: test/SemaCXX/overload-call.cpp
===
--- test/SemaCXX/overload-call.cpp
+++ test/SemaCXX/overload-call.cpp
@@ -574,13 +574,15 @@
   // Ensure that overload resolution attempts to complete argument types when
   // performing ADL.
   template struct S {
-friend int f(const S&);
+friend int f(const S&);  // expected-warning{{friend declaration 'IncompleteArg::f' depends on template parameter but is not a template function}}
+ // expected-note@-1{{if this is intentional, add function declaration to suppress the warning, if not - make sure the function template has already been declared and use '<>'}}
   };
   extern S s;
   int k = f(s);
 
   template struct Op {
-friend bool operator==(const Op &, const Op &);
+friend bool operator==(const Op &, const Op &);  // expected-warning{{friend declaration 'IncompleteArg::operator==' depends on template parameter but is not a template function}}
+ // expected-note@-1{{if this is intentional, add function declaration to suppress the warning, if not - make sure the function template has already been declared and use '<>'}}
   };
   extern Op op;
   bool b = op == op;
Index: test/SemaCXX/friend.cpp
===
--- test/SemaCXX/friend.cpp
+++ test/SemaCXX/friend.cpp
@@ -363,3 +363,102 @@
   f_pr6954(5); // expected-error{{undeclared identifier 'f_pr6954'}}
 }
 
+
+template void pr23342_func(T x);
+template
+struct pr23342_C1 {
+  friend void pr23342_func<>(T x);
+  friend bool func(T x);  // expected-warning{{friend declaration 'func' depends on template parameter but is not a template function}}
+  // expected-note@-1{{if this is intentional, add function declaration to suppress the warning, if not - make sure the function template has already been declared and use '<>'}}
+  friend bool func2(int x);
+  template friend bool func3(T2 x);
+  friend T func4();  // expected-warning{{friend declaration 'func4' depends on template parameter but is not a template function}}
+ // expected-note@-1{{if this is intentional, add function declaration to suppress the warning, if not - make sure the function template has already been declared and use '<>'}}
+};
+
+namespace pr23342 {
+
+template
+struct C1 {
+  friend void pr23342_func<>(T x);
+  friend bool func(T x);  // expected-warning{{friend declaration 'pr23342::func' depends on template parameter but is not a template function}}
+  // expected-note@-1{{if this is intentional, add function declaration to suppress the warning, if not - make sure the function template has already been declared and use '<>'}}
+  friend bool func2(int x);
+  template friend bool func3(T2 x);
+  friend T func4();// expected-warning{{friend declaration 'pr23342::func4' depends on template parameter but is not a template function}}
+   // expected-note@-1{{if this is intentional, add function declaration to suppress the warning, if not - make sure the function template has already been declared and use '<>'}}
+};
+
+template 
+struct Arg {
+  friend bool operator==(const Arg& lhs, T rhs) {
+   return false;
+  }
+  friend bool operator!=(const Arg& lhs, T rhs);  // expected-warning{{friend declaration 'pr23342::operator!=' depends on template parameter but is not a template function}}
+   // expected-note@-1{{to befriend a template specialization, use '<>'}}
+};
+template 
+bool operator!=(const Arg& lhs, T rhs) {
+  return true;
+}
+bool foo() {
+  Arg arg;
+  return (arg == 42) || (arg != 42);
+}
+
+
+template class C0 {
+  friend void func0(C0 &);  // expected-warning{{friend declaration 'pr23342::func0' depends on template parameter but is not a template function}}
+   // expected-note@-1{{if this is intentional, add function declaration to suppress the warning, if not - make sure the function template has already been declared and use '<>'}}
+};
+
+template class C0a {
+  friend void func0a(C0a &);  // expected-warning{{friend declaration 'pr23342::func0a' depends on template parameter but is not 

Re: [PATCH] D16579: Warn if friend function depends on template parameters.

2016-03-20 Thread Serge Pavlov via cfe-commits
2016-03-18 0:35 GMT+06:00 Arthur O'Dwyer :

> I'm not qualified to comment on the implementation, but I'm a bit
> skeptical that this warning is appropriate in the first place. I've often
> declared friend non-template functions, e.g. swap(). I've never intended to
> declare a friend *template specialization*. Is declaring friend template
> specializations something that people do often? Is it something that Clang
> should be encouraging newbies to do *more* often?
>

It is not about intention but misunderstanding. Users often think that if a
function is declared inside a template class and depends on template
parameters, it is template. That expect the following code to work:

template void foo(T *x) {…}
template class Bar {
  void foo(T *x);
}

There are lots of questions in forums (search by keywords "friend template
function link error"), in which people feel surprised why such code results
in undefined reference. The proposed compiler message is just a hint how to
make the code working as expected by a user.


>
> GCC suppresses the diagnostic when the friend function is declared inline,
> which is good, because it shuts up the diagnostic in this very common case:
>
> template
> struct vector {
> void swap(vector& b) { /* swap members */ }
> friend void swap(vector& a, vector& b) { a.swap(b); }  // friend
> non-template function
> };
>
> IMHO you should add an explicit test confirming that the warning is
> suppressed in this case.
>

There is such check already, file `test/SemaCXX/friend.cpp`:

template 
struct Arg {
  friend bool operator==(const Arg& lhs, T rhs) {
   return false;
  }
…
};
…
bool foo() {
  Arg arg;
  return (arg == 42) || (arg != 42);
}

Operator `==` is defined inline, no warning expected.


>
The example in PR23342 doesn't seem like a good example, because GCC gives
> not only the proposed warning for that code, but also a linker error; i.e.,
> there's no danger of someone accidentally getting wrong runtime behavior
> there. Is there a compelling
>

Clang behaves exactly the same, compilation eventually results in a linker
error.


> example of how someone could write code that has wrong runtime behavior,
> *and* which code would be *fixed* by the suggested addition of template<>?
> I think it's much more likely that the appropriate fix would be to move the
> function definition inline.
>

There seems to be no danger to get wrong behavior here, only undefined
symbols at link stage. If code builds, it works right.


> https://llvm.org/bugs/show_bug.cgi?id=23342
>
> Why did you need to suppress the warning in
> "test/CXX/temp/temp.decls/temp.friend/p1.cpp"? Unless I'm mistaken, GCC
> doesn't give the diagnostic on that file (and nor should it).
>
> my $.02,
>

Good catch, thank you for your $0.02 :) There is no point in warnings for
class members. Patch fixed accordingly.

Thanks,
--Serge
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D16579: Warn if friend function depends on template parameters.

2016-03-19 Thread Serge Pavlov via cfe-commits
sepavloff updated this revision to Diff 51017.
sepavloff added a comment.

Do not emit warning on class methods.


http://reviews.llvm.org/D16579

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaDecl.cpp
  test/CXX/drs/dr3xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/SemaCXX/friend.cpp
  test/SemaCXX/overload-call.cpp

Index: test/SemaCXX/overload-call.cpp
===
--- test/SemaCXX/overload-call.cpp
+++ test/SemaCXX/overload-call.cpp
@@ -574,13 +574,15 @@
   // Ensure that overload resolution attempts to complete argument types when
   // performing ADL.
   template struct S {
-friend int f(const S&);
+friend int f(const S&);  // expected-warning{{friend declaration 'IncompleteArg::f' declares a non-template function}}
+ // expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}
   };
   extern S s;
   int k = f(s);
 
   template struct Op {
-friend bool operator==(const Op &, const Op &);
+friend bool operator==(const Op &, const Op &);  // expected-warning{{friend declaration 'IncompleteArg::operator==' declares a non-template function}}
+ // expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}
   };
   extern Op op;
   bool b = op == op;
Index: test/SemaCXX/friend.cpp
===
--- test/SemaCXX/friend.cpp
+++ test/SemaCXX/friend.cpp
@@ -363,3 +363,47 @@
   f_pr6954(5); // expected-error{{undeclared identifier 'f_pr6954'}}
 }
 
+
+template void pr23342_func(T x);
+template
+struct pr23342_C1 {
+  friend void pr23342_func<>(T x);
+  friend bool func(T x);  // expected-warning{{friend declaration 'func' declares a non-template function}}
+  // expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}
+  friend bool func2(int x);
+  template friend bool func3(T2 x);
+  friend T func4();  // expected-warning{{friend declaration 'func4' declares a non-template function}}
+ // expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}
+};
+
+namespace pr23342 {
+
+template
+struct C1 {
+  friend void pr23342_func<>(T x);
+  friend bool func(T x);  // expected-warning{{friend declaration 'pr23342::func' declares a non-template function}}
+  // expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}
+  friend bool func2(int x);
+  template friend bool func3(T2 x);
+  friend T func4();// expected-warning{{friend declaration 'pr23342::func4' declares a non-template function}}
+   // expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}};
+};
+
+template 
+struct Arg {
+  friend bool operator==(const Arg& lhs, T rhs) {
+   return false;
+  }
+  friend bool operator!=(const Arg& lhs, T rhs);  // expected-warning{{friend declaration 'pr23342::operator!=' declares a non-template function}}
+   // expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}};
+};
+template 
+bool operator!=(const Arg& lhs, T rhs) {
+  return true;
+}
+bool foo() {
+  Arg arg;
+  return (arg == 42) || (arg != 42);
+}
+
+}
Index: test/CXX/drs/dr5xx.cpp
===
--- test/CXX/drs/dr5xx.cpp
+++ test/CXX/drs/dr5xx.cpp
@@ -581,8 +581,10 @@
 
 namespace dr557 { // dr557: yes
   template struct S {
-friend void f(S *);
-friend void g(S *);
+friend void f(S *);  // expected-warning{{friend declaration 'dr557::f' declares a non-template function}}
+// expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}
+friend void g(S *); // expected-warning{{friend declaration 'dr557::g' declares a non-template function}}
+// expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}
   };
   void x(S *p, S *q) {
 f(p);
Index: test/CXX/drs/dr3xx.cpp
===
--- test/CXX/drs/dr3xx.cpp
+++ test/CXX/drs/dr3xx.cpp
@@ -291,7 +291,8 @@
   template 

Re: [PATCH] D16579: Warn if friend function depends on template parameters.

Ping.

Thanks,
--Serge

2016-02-26 12:20 GMT+06:00 Serge Pavlov :

> Could someone provide a feedback?
>
> Thanks,
> --Serge
>
> 2016-01-26 20:55 GMT+06:00 Serge Pavlov :
>
>> sepavloff created this revision.
>> sepavloff added a subscriber: cfe-commits.
>>
>> Declaration of friend function may depend on template parameters,
>> however it does not become a template function:
>>
>> template class C1 {
>>   friend void func(T x);
>> };
>>
>> It may be not obvious for user, so compiler could emit a warning in
>> such case. This patch implements appropriate warning, the wording is
>> taken from GCC message. The patch fixes PR23342.
>>
>> http://reviews.llvm.org/D16579
>>
>> Files:
>>   include/clang/Basic/DiagnosticGroups.td
>>   include/clang/Basic/DiagnosticSemaKinds.td
>>   lib/Sema/SemaDecl.cpp
>>   test/CXX/drs/dr3xx.cpp
>>   test/CXX/drs/dr5xx.cpp
>>   test/CXX/temp/temp.decls/temp.friend/p1.cpp
>>   test/PCH/cxx-templates.cpp
>>   test/PCH/cxx-templates.h
>>   test/SemaCXX/friend.cpp
>>   test/SemaCXX/overload-call.cpp
>>
>>
>
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D16579: Warn if friend function depends on template parameters.

I'm not qualified to comment on the implementation, but I'm a bit skeptical
that this warning is appropriate in the first place. I've often declared
friend non-template functions, e.g. swap(). I've never intended to declare
a friend *template specialization*. Is declaring friend template
specializations something that people do often? Is it something that Clang
should be encouraging newbies to do *more* often?

GCC suppresses the diagnostic when the friend function is declared inline,
which is good, because it shuts up the diagnostic in this very common case:

template
struct vector {
void swap(vector& b) { /* swap members */ }
friend void swap(vector& a, vector& b) { a.swap(b); }  // friend
non-template function
};

IMHO you should add an explicit test confirming that the warning is
suppressed in this case.

The example in PR23342 doesn't seem like a good example, because GCC gives
not only the proposed warning for that code, but also a linker error; i.e.,
there's no danger of someone accidentally getting wrong runtime behavior
there. Is there a compelling example of how someone could write code that
has wrong runtime behavior, *and* which code would be *fixed* by the
suggested addition of template<>? I think it's much more likely that the
appropriate fix would be to move the function definition inline.
https://llvm.org/bugs/show_bug.cgi?id=23342

Why did you need to suppress the warning in
"test/CXX/temp/temp.decls/temp.friend/p1.cpp"? Unless I'm mistaken, GCC
doesn't give the diagnostic on that file (and nor should it).

my $.02,
–Arthur



On Thu, Mar 17, 2016 at 9:21 AM, Serge Pavlov via cfe-commits <
cfe-commits@lists.llvm.org> wrote:

> Ping.
>
> Thanks,
> --Serge
>
> 2016-02-26 12:20 GMT+06:00 Serge Pavlov :
>
>> Could someone provide a feedback?
>>
>> Thanks,
>> --Serge
>>
>> 2016-01-26 20:55 GMT+06:00 Serge Pavlov :
>>
>>> sepavloff created this revision.
>>> sepavloff added a subscriber: cfe-commits.
>>>
>>> Declaration of friend function may depend on template parameters,
>>> however it does not become a template function:
>>>
>>> template class C1 {
>>>   friend void func(T x);
>>> };
>>>
>>> It may be not obvious for user, so compiler could emit a warning in
>>> such case. This patch implements appropriate warning, the wording is
>>> taken from GCC message. The patch fixes PR23342.
>>>
>>> http://reviews.llvm.org/D16579
>>>
>>> Files:
>>>   include/clang/Basic/DiagnosticGroups.td
>>>   include/clang/Basic/DiagnosticSemaKinds.td
>>>   lib/Sema/SemaDecl.cpp
>>>   test/CXX/drs/dr3xx.cpp
>>>   test/CXX/drs/dr5xx.cpp
>>>   test/CXX/temp/temp.decls/temp.friend/p1.cpp
>>>   test/PCH/cxx-templates.cpp
>>>   test/PCH/cxx-templates.h
>>>   test/SemaCXX/friend.cpp
>>>   test/SemaCXX/overload-call.cpp
>>>
>>>
>>
>
> ___
> cfe-commits mailing list
> cfe-commits@lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
>
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D16579: Warn if friend function depends on template parameters.

rsmith added a subscriber: rsmith.
rsmith added a comment.

It seems useful to warn on this, but I'm concerned that there are valid code 
patterns that this will warn about where there is no reasonable way to rewrite 
the code that would suppress the warning. For instance:

  template class X {
friend void process(X);
// ...
  };
  void process(X) { /* ... */ }
  void process(X) ( /* ... */ }

As an alternative, can we suppress the warning until we see an "almost 
matching" template declaration in the surrounding scope? For instance:

  template void process(X) { /* ... */ } // warning, not a 
friend of X



Comment at: include/clang/Basic/DiagnosticSemaKinds.td:1155-1157
@@ -1153,1 +1154,5 @@
+  "non-template function">, InGroup;
+def note_non_template_friend : Note<"if this is not what you intended, make "
+  "sure the function template has already been declared and add <> after the "
+  "function name here">;
 

Maybe just: "to befriend a template specialization, use <>", along with a 
FixItHint showing where to add the <>.

It would also seem like a good idea to check if there is such a function 
template declared, and give different diagnostic if not.


http://reviews.llvm.org/D16579



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D16579: Warn if friend function depends on template parameters.

Could someone provide a feedback?

Thanks,
--Serge

2016-01-26 20:55 GMT+06:00 Serge Pavlov :

> sepavloff created this revision.
> sepavloff added a subscriber: cfe-commits.
>
> Declaration of friend function may depend on template parameters,
> however it does not become a template function:
>
> template class C1 {
>   friend void func(T x);
> };
>
> It may be not obvious for user, so compiler could emit a warning in
> such case. This patch implements appropriate warning, the wording is
> taken from GCC message. The patch fixes PR23342.
>
> http://reviews.llvm.org/D16579
>
> Files:
>   include/clang/Basic/DiagnosticGroups.td
>   include/clang/Basic/DiagnosticSemaKinds.td
>   lib/Sema/SemaDecl.cpp
>   test/CXX/drs/dr3xx.cpp
>   test/CXX/drs/dr5xx.cpp
>   test/CXX/temp/temp.decls/temp.friend/p1.cpp
>   test/PCH/cxx-templates.cpp
>   test/PCH/cxx-templates.h
>   test/SemaCXX/friend.cpp
>   test/SemaCXX/overload-call.cpp
>
>
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D16579: Warn if friend function depends on template parameters.

Any feedback?

Thanks,
--Serge

2016-01-26 20:55 GMT+06:00 Serge Pavlov :

> sepavloff created this revision.
> sepavloff added a subscriber: cfe-commits.
>
> Declaration of friend function may depend on template parameters,
> however it does not become a template function:
>
> template class C1 {
>   friend void func(T x);
> };
>
> It may be not obvious for user, so compiler could emit a warning in
> such case. This patch implements appropriate warning, the wording is
> taken from GCC message. The patch fixes PR23342.
>
> http://reviews.llvm.org/D16579
>
> Files:
>   include/clang/Basic/DiagnosticGroups.td
>   include/clang/Basic/DiagnosticSemaKinds.td
>   lib/Sema/SemaDecl.cpp
>   test/CXX/drs/dr3xx.cpp
>   test/CXX/drs/dr5xx.cpp
>   test/CXX/temp/temp.decls/temp.friend/p1.cpp
>   test/PCH/cxx-templates.cpp
>   test/PCH/cxx-templates.h
>   test/SemaCXX/friend.cpp
>   test/SemaCXX/overload-call.cpp
>
>
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D16579: Warn if friend function depends on template parameters.

sepavloff created this revision.
sepavloff added a subscriber: cfe-commits.

Declaration of friend function may depend on template parameters,
however it does not become a template function:

template class C1 {
  friend void func(T x);
};

It may be not obvious for user, so compiler could emit a warning in
such case. This patch implements appropriate warning, the wording is
taken from GCC message. The patch fixes PR23342.

http://reviews.llvm.org/D16579

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaDecl.cpp
  test/CXX/drs/dr3xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/CXX/temp/temp.decls/temp.friend/p1.cpp
  test/PCH/cxx-templates.cpp
  test/PCH/cxx-templates.h
  test/SemaCXX/friend.cpp
  test/SemaCXX/overload-call.cpp

Index: test/SemaCXX/overload-call.cpp
===
--- test/SemaCXX/overload-call.cpp
+++ test/SemaCXX/overload-call.cpp
@@ -566,13 +566,15 @@
   // Ensure that overload resolution attempts to complete argument types when
   // performing ADL.
   template struct S {
-friend int f(const S&);
+friend int f(const S&);  // expected-warning{{friend declaration 'IncompleteArg::f' declares a non-template function}}
+ // expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}
   };
   extern S s;
   int k = f(s);
 
   template struct Op {
-friend bool operator==(const Op &, const Op &);
+friend bool operator==(const Op &, const Op &);  // expected-warning{{friend declaration 'IncompleteArg::operator==' declares a non-template function}}
+ // expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}
   };
   extern Op op;
   bool b = op == op;
Index: test/SemaCXX/friend.cpp
===
--- test/SemaCXX/friend.cpp
+++ test/SemaCXX/friend.cpp
@@ -21,7 +21,8 @@
   template  struct Outer {
 void foo(T);
 struct Inner {
-  friend void Outer::foo(T);
+  friend void Outer::foo(T);  // expected-warning{{friend declaration 'test1::Outer::Inner::foo' declares a non-template function}}
+  // expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}
 };
   };
 
@@ -363,3 +364,47 @@
   f_pr6954(5); // expected-error{{undeclared identifier 'f_pr6954'}}
 }
 
+
+template void pr23342_func(T x);
+template
+struct pr23342_C1 {
+  friend void pr23342_func<>(T x);
+  friend bool func(T x);  // expected-warning{{friend declaration 'func' declares a non-template function}}
+  // expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}
+  friend bool func2(int x);
+  template friend bool func3(T2 x);
+  friend T func4();  // expected-warning{{friend declaration 'func4' declares a non-template function}}
+ // expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}
+};
+
+namespace pr23342 {
+
+template
+struct C1 {
+  friend void pr23342_func<>(T x);
+  friend bool func(T x);  // expected-warning{{friend declaration 'pr23342::func' declares a non-template function}}
+  // expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}
+  friend bool func2(int x);
+  template friend bool func3(T2 x);
+  friend T func4();// expected-warning{{friend declaration 'pr23342::func4' declares a non-template function}}
+   // expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}};
+};
+
+template 
+struct Arg {
+  friend bool operator==(const Arg& lhs, T rhs) {
+   return false;
+  }
+  friend bool operator!=(const Arg& lhs, T rhs);  // expected-warning{{friend declaration 'pr23342::operator!=' declares a non-template function}}
+   // expected-note@-1{{if this is not what you intended, make sure the function template has already been declared and add <> after the function name here}}};
+};
+template 
+bool operator!=(const Arg& lhs, T rhs) {
+  return true;
+}
+bool foo() {
+  Arg arg;
+  return (arg == 42) || (arg != 42);
+}
+
+}
Index: test/PCH/cxx-templates.h
===
--- test/PCH/cxx-templates.h
+++ test/PCH/cxx-templates.h
@@ -1,4 +1,5 @@
 // Header for PCH test cxx-templates.cpp