aaron.ballman created this revision.
aaron.ballman added reviewers: rsmith, rjmccall, erichkeane.
aaron.ballman requested review of this revision.
Herald added a project: clang.

The following was found by a customer and is accepted by the other primary C++ 
compilers, but fails to compile in Clang:

  namespace sss {
  double foo(int, double);
  template <class T>
  T foo(T); // note: target of using declaration
  }  // namespace sss
  
  namespace oad {
  void foo();
  }
  
  namespace oad {
  using ::sss::foo;
  }
  
  namespace sss {
  using oad::foo; // note: using declaration
  }
  
  namespace sss {
  double foo(int, double) { return 0; }
  template <class T>
  T foo(T t) { // error: declaration conflicts with target of using declaration 
already in scope
    return t;
  }
  }  // namespace sss

I believe the issue is that `MergeFunctionDecl()` was calling 
`checkUsingShadowRedecl()` but only considering a `FunctionDecl` as a possible 
shadow and not `FunctionTemplateDecl`. The changes in this patch largely mirror 
how variable declarations were being handled by also catching 
`FunctionTemplateDecl`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D103485

Files:
  clang/lib/Sema/SemaDecl.cpp
  clang/test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp
  clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp
  clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp
  clang/test/SemaCXX/using-decl-templates.cpp

Index: clang/test/SemaCXX/using-decl-templates.cpp
===================================================================
--- clang/test/SemaCXX/using-decl-templates.cpp
+++ clang/test/SemaCXX/using-decl-templates.cpp
@@ -101,3 +101,33 @@
   using Base<false>::Base; // OK. Don't diagnose that 'Base' isn't a base class of Derived.
 };
 } // namespace DontDiagnoseInvalidTest
+
+namespace func_templ {
+namespace sss {
+double foo(int, double);
+template <class T>
+T foo(T);
+} // namespace sss
+
+namespace oad {
+void foo();
+}
+
+namespace oad {
+using sss::foo;
+}
+
+namespace sss {
+using oad::foo;
+}
+
+namespace sss {
+double foo(int, double) { return 0; }
+// There used to be an error with the below declaration when the example should
+// be accepted.
+template <class T>
+T foo(T t) { // OK
+  return t;
+}
+} // namespace sss
+} // namespace func_templ
Index: clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp
===================================================================
--- clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp
+++ clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp
@@ -34,9 +34,9 @@
 using type = int;
 
 template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module N follows declaration in module M}} expected-n...@global-vs-module.cpp:43 {{previous}}
-template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in module N follows declaration in module M}} expected-n...@global-vs-module.cpp:45 {{previous}}
-template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in module N follows declaration in module M}} expected-n...@global-vs-module.cpp:46 {{previous}}
-template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module N follows declaration in module M}} expected-n...@global-vs-module.cpp:47 {{previous}}
+template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in module N follows declaration in module M}} expected-n...@global-vs-module.cpp:44 {{previous}}
+template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in module N follows declaration in module M}} expected-n...@global-vs-module.cpp:45 {{previous}}
+template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module N follows declaration in module M}} expected-n...@global-vs-module.cpp:46 {{previous}}
 
 typedef int type;
 namespace ns { using ::func; }
Index: clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp
===================================================================
--- clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp
+++ clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp
@@ -10,9 +10,9 @@
 using type = int;
 
 template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in the global module follows declaration in module M}} expected-n...@global-vs-module.cpp:43 {{previous}}
-template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in the global module follows declaration in module M}} expected-n...@global-vs-module.cpp:45 {{previous}}
-template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in the global module follows declaration in module M}} expected-n...@global-vs-module.cpp:46 {{previous}}
-template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in the global module follows declaration in module M}} expected-n...@global-vs-module.cpp:47 {{previous}}
+template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in the global module follows declaration in module M}} expected-n...@global-vs-module.cpp:44 {{previous}}
+template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in the global module follows declaration in module M}} expected-n...@global-vs-module.cpp:45 {{previous}}
+template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in the global module follows declaration in module M}} expected-n...@global-vs-module.cpp:46 {{previous}}
 
 typedef int type;
 namespace ns { using ::func; }
Index: clang/test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp
===================================================================
--- clang/test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp
+++ clang/test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp
@@ -9,7 +9,7 @@
 using type = int;
 
 template<typename> extern int var_tpl; // expected-note {{previous declaration is here}}
-template<typename> int func_tpl(); // expected-note-re {{{{previous declaration is here|target of using declaration}}}}
+template<typename> int func_tpl(); // expected-note {{previous declaration is here}}
 template<typename> struct str_tpl; // expected-note {{previous declaration is here}}
 template<typename> using type_tpl = int; // expected-note {{previous declaration is here}}
 
@@ -26,7 +26,7 @@
 using ::str;
 using ::type;
 using ::var_tpl;
-using ::func_tpl; // expected-note {{using declaration}}
+using ::func_tpl;
 using ::str_tpl;
 using ::type_tpl;
 #endif
@@ -41,8 +41,7 @@
 using type = int;
 
 template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module M follows declaration in the global module}}
-// FIXME: Is this the right diagnostic in the -DUSING case?
-template<typename> int func_tpl(); // expected-error-re {{{{declaration of 'func_tpl' in module M follows declaration in the global module|conflicts with target of using declaration}}}}
+template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in module M follows declaration in the global module}}
 template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in module M follows declaration in the global module}}
 template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module M follows declaration in the global module}}
 
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -3113,6 +3113,7 @@
 
 template<typename T> static bool isExternC(T *D) { return D->isExternC(); }
 static bool isExternC(VarTemplateDecl *) { return false; }
+static bool isExternC(FunctionTemplateDecl *) { return false; }
 
 /// Check whether a redeclaration of an entity introduced by a
 /// using-declaration is valid, given that we know it's not an overload
@@ -3237,10 +3238,20 @@
         return true;
       }
 
-      // Check whether the two declarations might declare the same function.
-      if (checkUsingShadowRedecl<FunctionDecl>(*this, Shadow, New))
-        return true;
-      OldD = Old = cast<FunctionDecl>(Shadow->getTargetDecl());
+      // Check whether the two declarations might declare the same function or
+      // function template.
+      if (FunctionTemplateDecl *NewTemplate =
+              New->getDescribedFunctionTemplate()) {
+        if (checkUsingShadowRedecl<FunctionTemplateDecl>(*this, Shadow,
+                                                         NewTemplate))
+          return true;
+        OldD = Old = cast<FunctionTemplateDecl>(Shadow->getTargetDecl())
+                         ->getAsFunction();
+      } else {
+        if (checkUsingShadowRedecl<FunctionDecl>(*this, Shadow, New))
+          return true;
+        OldD = Old = cast<FunctionDecl>(Shadow->getTargetDecl());
+      }
     } else {
       Diag(New->getLocation(), diag::err_redefinition_different_kind)
         << New->getDeclName();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to