Commit f0ed63b7 authored by Tom Stellard's avatar Tom Stellard
Browse files

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
parent ea49dcd1
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -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
+3 −8
Original line number Diff line number Diff line
@@ -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())
+2 −1
Original line number Diff line number Diff line
@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -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;
+70 −0
Original line number Diff line number Diff line
@@ -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}}
}