Author: Aaron Ballman Date: 2021-06-04T15:52:07-04:00 New Revision: ca68f3bc48e48f839142de1461e95d87ae48e9df
URL: https://github.com/llvm/llvm-project/commit/ca68f3bc48e48f839142de1461e95d87ae48e9df DIFF: https://github.com/llvm/llvm-project/commit/ca68f3bc48e48f839142de1461e95d87ae48e9df.diff LOG: Fix a diagnoses-valid bug with using declarations 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 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. Added: Modified: 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 Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 0abdd31b43ec3..4f62113dd8e60 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3165,6 +3165,7 @@ static bool haveIncompatibleLanguageLinkages(const T *Old, const T *New) { 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 @@ -3289,10 +3290,20 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, 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_ diff erent_kind) << New->getDeclName(); diff --git a/clang/test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp b/clang/test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp index cceca5106cae9..a16374a80099e 100644 --- a/clang/test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp +++ b/clang/test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp @@ -9,7 +9,7 @@ struct str; // expected-note {{previous declaration is here}} 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 ::func; 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 @@ struct str; // expected-error {{declaration of 'str' in module M follows declara 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}} diff --git a/clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp b/clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp index f58506dd9c46d..50c153a25c1a2 100644 --- a/clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp +++ b/clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp @@ -10,9 +10,9 @@ struct str; // expected-error {{declaration of 'str' in the global module follow 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; } diff --git a/clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp b/clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp index 39e210c4ad806..4c5cb2905cee1 100644 --- a/clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp +++ b/clang/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp @@ -34,9 +34,9 @@ struct str; // expected-error {{declaration of 'str' in module N follows declara 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; } diff --git a/clang/test/SemaCXX/using-decl-templates.cpp b/clang/test/SemaCXX/using-decl-templates.cpp index d5cc3a08eb758..d825971954ec2 100644 --- a/clang/test/SemaCXX/using-decl-templates.cpp +++ b/clang/test/SemaCXX/using-decl-templates.cpp @@ -101,3 +101,33 @@ struct Derived : Base<false> { // expected-note {{requested here}} 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits