forked from OSchip/llvm-project
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.
This commit is contained in:
parent
1e6d135325
commit
ca68f3bc48
|
@ -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_different_kind)
|
||||
<< New->getDeclName();
|
||||
|
|
|
@ -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}}
|
||||
|
||||
|
|
|
@ -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@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@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@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@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@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@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@global-vs-module.cpp:46 {{previous}}
|
||||
|
||||
typedef int type;
|
||||
namespace ns { using ::func; }
|
||||
|
|
|
@ -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@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@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@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@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@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@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@global-vs-module.cpp:46 {{previous}}
|
||||
|
||||
typedef int type;
|
||||
namespace ns { using ::func; }
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue