mirror of https://github.com/microsoft/clang.git
PR33222: Require the declared return type not the actual return type to
match when checking for redeclaration of a function template. This properly handles differences in deduced return types, particularly when performing redeclaration checks for a friend function template. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@341778 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
3b7400d6f4
commit
26751adfec
|
@ -2269,8 +2269,7 @@ public:
|
|||
unsigned getMinRequiredArguments() const;
|
||||
|
||||
QualType getReturnType() const {
|
||||
assert(getType()->getAs<FunctionType>() && "Expected a FunctionType!");
|
||||
return getType()->getAs<FunctionType>()->getReturnType();
|
||||
return getType()->castAs<FunctionType>()->getReturnType();
|
||||
}
|
||||
|
||||
/// Attempt to compute an informative source range covering the
|
||||
|
@ -2278,14 +2277,22 @@ public:
|
|||
/// limited representation in the AST.
|
||||
SourceRange getReturnTypeSourceRange() const;
|
||||
|
||||
/// Get the declared return type, which may differ from the actual return
|
||||
/// type if the return type is deduced.
|
||||
QualType getDeclaredReturnType() const {
|
||||
auto *TSI = getTypeSourceInfo();
|
||||
QualType T = TSI ? TSI->getType() : getType();
|
||||
return T->castAs<FunctionType>()->getReturnType();
|
||||
}
|
||||
|
||||
/// Attempt to compute an informative source range covering the
|
||||
/// function exception specification, if any.
|
||||
SourceRange getExceptionSpecSourceRange() const;
|
||||
|
||||
/// Determine the type of an expression that calls this function.
|
||||
QualType getCallResultType() const {
|
||||
assert(getType()->getAs<FunctionType>() && "Expected a FunctionType!");
|
||||
return getType()->getAs<FunctionType>()->getCallResultType(getASTContext());
|
||||
return getType()->castAs<FunctionType>()->getCallResultType(
|
||||
getASTContext());
|
||||
}
|
||||
|
||||
/// Returns the WarnUnusedResultAttr that is either declared on this
|
||||
|
|
|
@ -3245,20 +3245,15 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
|
|||
// Redeclarations or specializations of a function or function template
|
||||
// with a declared return type that uses a placeholder type shall also
|
||||
// use that placeholder, not a deduced type.
|
||||
QualType OldDeclaredReturnType =
|
||||
(Old->getTypeSourceInfo()
|
||||
? Old->getTypeSourceInfo()->getType()->castAs<FunctionType>()
|
||||
: OldType)->getReturnType();
|
||||
QualType NewDeclaredReturnType =
|
||||
(New->getTypeSourceInfo()
|
||||
? New->getTypeSourceInfo()->getType()->castAs<FunctionType>()
|
||||
: NewType)->getReturnType();
|
||||
QualType OldDeclaredReturnType = Old->getDeclaredReturnType();
|
||||
QualType NewDeclaredReturnType = New->getDeclaredReturnType();
|
||||
if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType) &&
|
||||
canFullyTypeCheckRedeclaration(New, Old, NewDeclaredReturnType,
|
||||
OldDeclaredReturnType)) {
|
||||
QualType ResQT;
|
||||
if (NewDeclaredReturnType->isObjCObjectPointerType() &&
|
||||
OldDeclaredReturnType->isObjCObjectPointerType())
|
||||
// FIXME: This does the wrong thing for a deduced return type.
|
||||
ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType);
|
||||
if (ResQT.isNull()) {
|
||||
if (New->isCXXClassMember() && New->isOutOfLine())
|
||||
|
|
|
@ -1105,7 +1105,8 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
|
|||
(!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
|
||||
OldTemplate->getTemplateParameters(),
|
||||
false, TPL_TemplateMatch) ||
|
||||
OldType->getReturnType() != NewType->getReturnType()))
|
||||
!Context.hasSameType(Old->getDeclaredReturnType(),
|
||||
New->getDeclaredReturnType())))
|
||||
return true;
|
||||
|
||||
// If the function is a class member, its signature includes the
|
||||
|
|
|
@ -8294,6 +8294,8 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
|
|||
QualType Adjusted = Function->getType();
|
||||
if (!hasExplicitCallingConv(Adjusted))
|
||||
Adjusted = adjustCCAndNoReturn(Adjusted, Method->getType());
|
||||
// This doesn't handle deduced return types, but both function
|
||||
// declarations should be undeduced at this point.
|
||||
if (Context.hasSameType(Adjusted, Method->getType())) {
|
||||
FoundInstantiation = *I;
|
||||
Instantiation = Method;
|
||||
|
|
|
@ -552,3 +552,73 @@ namespace PR24989 {
|
|||
void forinit_decltypeauto() {
|
||||
for (decltype(auto) forinit_decltypeauto_inner();;) {} // expected-warning {{interpreted as a function}} expected-note {{replace}}
|
||||
}
|
||||
|
||||
namespace PR33222 {
|
||||
auto f1();
|
||||
auto f2();
|
||||
|
||||
template<typename T> decltype(auto) g0(T x) { return x.n; }
|
||||
template<typename T> decltype(auto) g1(T);
|
||||
template<typename T> decltype(auto) g2(T);
|
||||
|
||||
struct X {
|
||||
static auto f1();
|
||||
static auto f2();
|
||||
|
||||
template<typename T> static decltype(auto) g0(T x) { return x.n; } // FIXME (PR38883): expected-error {{private}}
|
||||
template<typename T> static decltype(auto) g1(T);
|
||||
template<typename T> static decltype(auto) g2(T);
|
||||
};
|
||||
|
||||
template<typename U> class A {
|
||||
friend auto f1();
|
||||
friend auto f2();
|
||||
|
||||
// FIXME (PR38883): This friend declaration doesn't actually work, because
|
||||
// we fail to look up the named function properly during instantiation.
|
||||
friend decltype(auto) g0<>(A);
|
||||
template<typename T> friend decltype(auto) g1(T);
|
||||
template<typename T> friend decltype(auto) g2(T);
|
||||
|
||||
friend auto X::f1();
|
||||
friend auto X::f2();
|
||||
|
||||
// FIXME (PR38882): 'A' names the class template not the injected-class-name here!
|
||||
friend decltype(auto) X::g0<>(A<U>);
|
||||
// FIXME (PR38882): ::T hides the template parameter if both are named T here!
|
||||
template<typename T_> friend decltype(auto) X::g1(T_);
|
||||
template<typename T_> friend decltype(auto) X::g2(T_);
|
||||
|
||||
int n; // FIXME: expected-note {{here}}
|
||||
};
|
||||
|
||||
auto f1() { return A<int>().n; }
|
||||
template<typename T> decltype(auto) g1(T x) { return A<int>().n; }
|
||||
|
||||
auto X::f1() { return A<int>().n; }
|
||||
template<typename T> decltype(auto) X::g1(T x) { return A<int>().n; }
|
||||
|
||||
A<int> ai;
|
||||
int k1 = g0(ai);
|
||||
int k2 = X::g0(ai); // FIXME: expected-note {{in instantiation of}}
|
||||
|
||||
int k3 = g1(ai);
|
||||
int k4 = X::g1(ai);
|
||||
|
||||
auto f2() { return A<int>().n; }
|
||||
template<typename T> decltype(auto) g2(T x) { return A<int>().n; }
|
||||
|
||||
auto X::f2() { return A<int>().n; }
|
||||
template<typename T> decltype(auto) X::g2(T x) { return A<int>().n; }
|
||||
|
||||
int k5 = g2(ai);
|
||||
int k6 = X::g2(ai);
|
||||
|
||||
template<typename> struct B {
|
||||
auto *q() { return (float*)0; } // expected-note 2{{previous}}
|
||||
};
|
||||
template<> auto *B<char[1]>::q() { return (int*)0; }
|
||||
template<> auto B<char[2]>::q() { return (int*)0; } // expected-error {{return type}}
|
||||
// FIXME: suppress this follow-on error: expected-error@-1 {{cannot initialize}}
|
||||
template<> int B<char[3]>::q() { return 0; } // expected-error {{return type}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue