Implement most of N3638 (return type deduction for normal functions).
Missing (somewhat ironically) is support for the new deduction rules
in lambda functions, plus PCH support for return type patching.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181108 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 16cc43a..248665a 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -2482,12 +2482,80 @@
   return Owned(Result);
 }
 
+/// Deduce the return type for a function from a returned expression, per
+/// C++1y [dcl.spec.auto]p6.
+bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
+                                            SourceLocation ReturnLoc,
+                                            Expr *&RetExpr,
+                                            AutoType *AT) {
+  TypeLoc OrigResultType = FD->getTypeSourceInfo()->getTypeLoc().
+    IgnoreParens().castAs<FunctionProtoTypeLoc>().getResultLoc();
+  QualType Deduced;
+
+  if (RetExpr) {
+    //  If the deduction is for a return statement and the initializer is
+    //  a braced-init-list, the program is ill-formed.
+    if (isa<InitListExpr>(RetExpr)) {
+      Diag(RetExpr->getExprLoc(), diag::err_auto_fn_return_init_list);
+      return true;
+    }
+
+    //  Otherwise, [...] deduce a value for U using the rules of template
+    //  argument deduction.
+    DeduceAutoResult DAR = DeduceAutoType(OrigResultType, RetExpr, Deduced);
+
+    if (DAR == DAR_Failed && !FD->isInvalidDecl())
+      Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure)
+        << OrigResultType.getType() << RetExpr->getType();
+
+    if (DAR != DAR_Succeeded)
+      return true;
+  } else {
+    //  In the case of a return with no operand, the initializer is considered
+    //  to be void().
+    //
+    // Deduction here can only succeed if the return type is exactly 'cv auto'
+    // or 'decltype(auto)', so just check for that case directly.
+    if (!OrigResultType.getType()->getAs<AutoType>()) {
+      Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto)
+        << OrigResultType.getType();
+      return true;
+    }
+    // We always deduce U = void in this case.
+    Deduced = SubstAutoType(OrigResultType.getType(), Context.VoidTy);
+    if (Deduced.isNull())
+      return true;
+  }
+
+  //  If a function with a declared return type that contains a placeholder type
+  //  has multiple return statements, the return type is deduced for each return
+  //  statement. [...] if the type deduced is not the same in each deduction,
+  //  the program is ill-formed.
+  if (AT->isDeduced() && !FD->isInvalidDecl()) {
+    AutoType *NewAT = Deduced->getContainedAutoType();
+    if (!Context.hasSameType(AT->getDeducedType(), NewAT->getDeducedType())) {
+      Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
+        << (AT->isDecltypeAuto() ? 1 : 0)
+        << NewAT->getDeducedType() << AT->getDeducedType();
+      return true;
+    }
+  } else if (!FD->isInvalidDecl()) {
+    // Update all declarations of the function to have the deduced return type.
+    Context.adjustDeducedFunctionResultType(FD, Deduced);
+  }
+
+  return false;
+}
+
 StmtResult
 Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
   // Check for unexpanded parameter packs.
   if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp))
     return StmtError();
 
+  // FIXME: Unify this and C++1y auto function handling. In particular, we
+  // should allow 'return { 1, 2, 3 };' in a lambda to deduce
+  // 'std::initializer_list<int>'.
   if (isa<CapturingScopeInfo>(getCurFunction()))
     return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp);
 
@@ -2510,6 +2578,23 @@
   } else // If we don't have a function/method context, bail.
     return StmtError();
 
+  // FIXME: Add a flag to the ScopeInfo to indicate whether we're performing
+  // deduction.
+  bool HasDependentReturnType = FnRetType->isDependentType();
+  if (getLangOpts().CPlusPlus1y) {
+    if (AutoType *AT = FnRetType->getContainedAutoType()) {
+      FunctionDecl *FD = cast<FunctionDecl>(CurContext);
+      if (CurContext->isDependentContext())
+        HasDependentReturnType = true;
+      else if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) {
+        FD->setInvalidDecl();
+        return StmtError();
+      } else {
+        FnRetType = FD->getResultType();
+      }
+    }
+  }
+
   ReturnStmt *Result = 0;
   if (FnRetType->isVoidType()) {
     if (RetValExp) {
@@ -2575,7 +2660,7 @@
     }
 
     Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0);
-  } else if (!RetValExp && !FnRetType->isDependentType()) {
+  } else if (!RetValExp && !HasDependentReturnType) {
     unsigned DiagID = diag::warn_return_missing_expr;  // C90 6.6.6.4p4
     // C99 6.8.6.4p1 (ext_ since GCC warns)
     if (getLangOpts().C99) DiagID = diag::ext_return_missing_expr;
@@ -2586,9 +2671,9 @@
       Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/;
     Result = new (Context) ReturnStmt(ReturnLoc);
   } else {
-    assert(RetValExp || FnRetType->isDependentType());
+    assert(RetValExp || HasDependentReturnType);
     const VarDecl *NRVOCandidate = 0;
-    if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
+    if (!HasDependentReturnType && !RetValExp->isTypeDependent()) {
       // we have a non-void function with an expression, continue checking
 
       QualType RetType = (RelatedRetType.isNull() ? FnRetType : RelatedRetType);