[clang] ca68f3b - Fix a diagnoses-valid bug with using declarations
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 4 12:52:17 PDT 2021
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-note at 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-note at 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-note at 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-note at 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-note at 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-note at 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-note at 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-note at 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-note at 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-note at 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-note at 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-note at 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-note at 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-note at 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
More information about the cfe-commits
mailing list