diff options
author | Tom Stellard <tstellar@redhat.com> | 2018-10-26 17:59:43 +0000 |
---|---|---|
committer | Tom Stellard <tstellar@redhat.com> | 2018-10-26 17:59:43 +0000 |
commit | f0ed63b765aad78b1dd2642fa641e3468389a329 (patch) | |
tree | ef7f4505b66c931c1cd15cbd97e4e60a8f4c13dc | |
parent | ea49dcd184eda2426a4042631aa3cbbc5fa3b6df (diff) | |
download | llvm-f0ed63b765aad78b1dd2642fa641e3468389a329.zip llvm-f0ed63b765aad78b1dd2642fa641e3468389a329.tar.gz llvm-f0ed63b765aad78b1dd2642fa641e3468389a329.tar.bz2 |
Merging r341778:
------------------------------------------------------------------------
r341778 | rsmith | 2018-09-09 23:35:32 -0700 (Sun, 09 Sep 2018) | 5 lines
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.
------------------------------------------------------------------------
llvm-svn: 345412
-rw-r--r-- | clang/include/clang/AST/Decl.h | 15 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 11 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 2 | ||||
-rw-r--r-- | clang/test/SemaCXX/cxx1y-deduced-return-type.cpp | 70 |
5 files changed, 88 insertions, 13 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 6885968..2928443 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -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 diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index cdf412a..40384fa 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3249,20 +3249,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()) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 08af485..244c66f 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -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 diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index fa002de..9d6cd7d 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -8304,6 +8304,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; diff --git a/clang/test/SemaCXX/cxx1y-deduced-return-type.cpp b/clang/test/SemaCXX/cxx1y-deduced-return-type.cpp index 13ff751..5daba67 100644 --- a/clang/test/SemaCXX/cxx1y-deduced-return-type.cpp +++ b/clang/test/SemaCXX/cxx1y-deduced-return-type.cpp @@ -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}} +} |