summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Stellard <tstellar@redhat.com>2018-10-26 17:59:43 +0000
committerTom Stellard <tstellar@redhat.com>2018-10-26 17:59:43 +0000
commit6c8c4d998cbdea291d3a226dc04ca5e2f6bc9e1b (patch)
treec60df6619b9914c94df0ceab99566dabe65f4578
parent64138722d18d0c5140b47a5f5ce8807b62e7f598 (diff)
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. ------------------------------------------------------------------------
-rw-r--r--clang/include/clang/AST/Decl.h15
-rw-r--r--clang/lib/Sema/SemaDecl.cpp11
-rw-r--r--clang/lib/Sema/SemaOverload.cpp3
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp2
-rw-r--r--clang/test/SemaCXX/cxx1y-deduced-return-type.cpp70
5 files changed, 88 insertions, 13 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 6885968bae6..29284435ebe 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 cdf412aacc4..40384fa6a43 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 08af485ef4c..244c66f6939 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 fa002de3f5f..9d6cd7d555d 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 13ff751acae..5daba67bc56 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}}
+}