aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ASTContext.h3
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td17
-rw-r--r--include/clang/Sema/Sema.h8
-rw-r--r--include/clang/Sema/TemplateDeduction.h4
-rw-r--r--lib/AST/ASTContext.cpp38
-rw-r--r--lib/Sema/SemaDecl.cpp56
-rw-r--r--lib/Sema/SemaExpr.cpp12
-rw-r--r--lib/Sema/SemaOverload.cpp20
-rw-r--r--lib/Sema/SemaStmt.cpp91
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp78
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp12
-rw-r--r--lib/Sema/SemaType.cpp15
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp33
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6-1y.cpp31
-rw-r--r--test/SemaCXX/cxx1y-deduced-return-type.cpp338
-rw-r--r--www/cxx_status.html2
16 files changed, 708 insertions, 50 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 65f29c4815..902ded55f8 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -867,6 +867,9 @@ public:
const FunctionType *adjustFunctionType(const FunctionType *Fn,
FunctionType::ExtInfo EInfo);
+ /// \brief Change the result type of a function type once it is deduced.
+ void adjustDeducedFunctionResultType(FunctionDecl *FD, QualType ResultType);
+
/// \brief Return the uniqued reference to the type for a complex
/// number with the specified element type.
QualType getComplexType(QualType T) const;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index d7347e9c31..23e4edf09d 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1477,6 +1477,23 @@ def err_decltype_auto_compound_type : Error<
def err_decltype_auto_initializer_list : Error<
"cannot deduce 'decltype(auto)' from initializer list">;
+// C++1y deduced return types
+def err_auto_fn_deduction_failure : Error<
+ "cannot deduce return type %0 from returned value of type %1">;
+def err_auto_fn_different_deductions : Error<
+ "'%select{auto|decltype(auto)}0' in return type deduced as %1 here but "
+ "deduced as %2 in earlier return statement">;
+def err_auto_fn_used_before_defined : Error<
+ "function %0 with deduced return type cannot be used before it is defined">;
+def err_auto_fn_no_return_but_not_auto : Error<
+ "cannot deduce return type %0 for function with no return statements">;
+def err_auto_fn_return_void_but_not_auto : Error<
+ "cannot deduce return type %0 from omitted return expression">;
+def err_auto_fn_return_init_list : Error<
+ "cannot deduce return type from initializer list">;
+def err_auto_fn_virtual : Error<
+ "function with deduced return type cannot be virtual">;
+
// C++11 override control
def override_keyword_only_allowed_on_virtual_member_functions : Error<
"only virtual member functions can be marked '%0'">;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 78b9f1ee5a..0e6cc440ea 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -5667,8 +5667,16 @@ public:
DeduceAutoResult DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer,
QualType &Result);
+ DeduceAutoResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer,
+ QualType &Result);
QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement);
void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
+ bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
+ bool Diagnose = true);
+
+ bool DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
+ SourceLocation ReturnLoc,
+ Expr *&RetExpr, AutoType *AT);
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
diff --git a/include/clang/Sema/TemplateDeduction.h b/include/clang/Sema/TemplateDeduction.h
index 3abb8f1889..8292045fdb 100644
--- a/include/clang/Sema/TemplateDeduction.h
+++ b/include/clang/Sema/TemplateDeduction.h
@@ -157,8 +157,8 @@ public:
/// \brief The expression which caused a deduction failure.
///
/// TDK_FailedOverloadResolution: this argument is the reference to
- // an overloaded function which could not be resolved to a specific
- // function.
+ /// an overloaded function which could not be resolved to a specific
+ /// function.
Expr *Expression;
};
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index f4e53e6105..b827dc1080 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -2036,6 +2036,16 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
return cast<FunctionType>(Result.getTypePtr());
}
+void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
+ QualType ResultType) {
+ // FIXME: Need to inform serialization code about this!
+ for (FD = FD->getMostRecentDecl(); FD; FD = FD->getPreviousDecl()) {
+ const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>();
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ FD->setType(getFunctionType(ResultType, FPT->getArgTypes(), EPI));
+ }
+}
+
/// getComplexType - Return the uniqued reference to the type for a complex
/// number with the specified element type.
QualType ASTContext::getComplexType(QualType T) const {
@@ -3564,18 +3574,20 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,
return QualType(Ty, 0);
}
-/// getAutoType - We only unique auto types after they've been deduced.
-QualType ASTContext::getAutoType(QualType DeducedType,
- bool IsDecltypeAuto,
+/// getAutoType - Return the uniqued reference to the 'auto' type which has been
+/// deduced to the given type, or to the canonical undeduced 'auto' type, or the
+/// canonical deduced-but-dependent 'auto' type.
+QualType ASTContext::getAutoType(QualType DeducedType, bool IsDecltypeAuto,
bool IsDependent) const {
+ if (DeducedType.isNull() && !IsDecltypeAuto && !IsDependent)
+ return getAutoDeductType();
+
+ // Look in the folding set for an existing type.
void *InsertPos = 0;
- if (!DeducedType.isNull()) {
- // Look in the folding set for an existing type.
- llvm::FoldingSetNodeID ID;
- AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent);
- if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
- return QualType(AT, 0);
- }
+ llvm::FoldingSetNodeID ID;
+ AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent);
+ if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(AT, 0);
AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType,
IsDecltypeAuto,
@@ -3617,8 +3629,10 @@ QualType ASTContext::getAtomicType(QualType T) const {
/// getAutoDeductType - Get type pattern for deducing against 'auto'.
QualType ASTContext::getAutoDeductType() const {
if (AutoDeductTy.isNull())
- AutoDeductTy = getAutoType(QualType(), false);
- assert(!AutoDeductTy.isNull() && "can't build 'auto' pattern");
+ AutoDeductTy = QualType(
+ new (*this, TypeAlignment) AutoType(QualType(), /*decltype(auto)*/false,
+ /*dependent*/false),
+ 0);
return AutoDeductTy;
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index f7826771cc..06697fafe6 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2441,12 +2441,22 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
// Certain function declarations cannot be overloaded:
// -- Function declarations that differ only in the return type
// cannot be overloaded.
- QualType OldReturnType = OldType->getResultType();
- QualType NewReturnType = cast<FunctionType>(NewQType)->getResultType();
+
+ // Go back to the type source info to compare the declared return types,
+ // per C++1y [dcl.type.auto]p??:
+ // 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)->getResultType();
+ QualType NewDeclaredReturnType = (New->getTypeSourceInfo()
+ ? New->getTypeSourceInfo()->getType()->castAs<FunctionType>()
+ : NewType)->getResultType();
QualType ResQT;
- if (OldReturnType != NewReturnType) {
- if (NewReturnType->isObjCObjectPointerType()
- && OldReturnType->isObjCObjectPointerType())
+ if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType)) {
+ if (NewDeclaredReturnType->isObjCObjectPointerType() &&
+ OldDeclaredReturnType->isObjCObjectPointerType())
ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType);
if (ResQT.isNull()) {
if (New->isCXXClassMember() && New->isOutOfLine())
@@ -2461,8 +2471,21 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
NewQType = ResQT;
}
- const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
- CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
+ QualType OldReturnType = OldType->getResultType();
+ QualType NewReturnType = cast<FunctionType>(NewQType)->getResultType();
+ if (OldReturnType != NewReturnType) {
+ // If this function has a deduced return type and has already been
+ // defined, copy the deduced value from the old declaration.
+ AutoType *OldAT = Old->getResultType()->getContainedAutoType();
+ if (OldAT && OldAT->isDeduced()) {
+ New->setType(SubstAutoType(New->getType(), OldAT->getDeducedType()));
+ NewQType = Context.getCanonicalType(
+ SubstAutoType(NewQType, OldAT->getDeducedType()));
+ }
+ }
+
+ const CXXMethodDecl *OldMethod = dyn_cast<CXXMethodDecl>(Old);
+ CXXMethodDecl *NewMethod = dyn_cast<CXXMethodDecl>(New);
if (OldMethod && NewMethod) {
// Preserve triviality.
NewMethod->setTrivial(OldMethod->isTrivial());
@@ -6047,6 +6070,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Okay: Add virtual to the method.
NewFD->setVirtualAsWritten(true);
}
+
+ if (getLangOpts().CPlusPlus1y &&
+ NewFD->getResultType()->isUndeducedType())
+ Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_auto_fn_virtual);
}
// C++ [dcl.fct.spec]p3:
@@ -8860,6 +8887,21 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (FD) {
FD->setBody(Body);
+ if (getLangOpts().CPlusPlus1y && !FD->isInvalidDecl() &&
+ !FD->isDependentContext()) {
+ if (FD->getResultType()->isUndeducedType()) {
+ // If the function has a deduced result type but contains no 'return'
+ // statements, the result type as written must be exactly 'auto', and
+ // the deduced result type is 'void'.
+ if (!FD->getResultType()->getAs<AutoType>()) {
+ Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto)
+ << FD->getResultType();
+ FD->setInvalidDecl();
+ }
+ Context.adjustDeducedFunctionResultType(FD, Context.VoidTy);
+ }
+ }
+
// The only way to be included in UndefinedButUsed is if there is an
// ODR use before the definition. Avoid the expensive map lookup if this
// is the first declaration.
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 60dbdc14be..2acbe5961e 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -55,6 +55,12 @@ bool Sema::CanUseDecl(NamedDecl *D) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isDeleted())
return false;
+
+ // If the function has a deduced return type, and we can't deduce it,
+ // then we can't use it either.
+ if (getLangOpts().CPlusPlus1y && FD->getResultType()->isUndeducedType() &&
+ DeduceReturnType(FD, SourceLocation(), /*Diagnose*/false))
+ return false;
}
// See if this function is unavailable.
@@ -278,6 +284,12 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
NoteDeletedFunction(FD);
return true;
}
+
+ // If the function has a deduced return type, and we can't deduce it,
+ // then we can't use it either.
+ if (getLangOpts().CPlusPlus1y && FD->getResultType()->isUndeducedType() &&
+ DeduceReturnType(FD, Loc))
+ return true;
}
DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass);
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 480c4a0d2b..e59c811186 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -5726,6 +5726,14 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
if (!CandidateSet.isNewCandidate(Conversion))
return;
+ // If the conversion function has an undeduced return type, trigger its
+ // deduction now.
+ if (getLangOpts().CPlusPlus1y && ConvType->isUndeducedType()) {
+ if (DeduceReturnType(Conversion, From->getExprLoc()))
+ return;
+ ConvType = Conversion->getConversionType().getNonReferenceType();
+ }
+
// Overload resolution is always an unevaluated context.
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
@@ -9173,6 +9181,13 @@ private:
if (S.CheckCUDATarget(Caller, FunDecl))
return false;
+ // If any candidate has a placeholder return type, trigger its deduction
+ // now.
+ if (S.getLangOpts().CPlusPlus1y &&
+ FunDecl->getResultType()->isUndeducedType() &&
+ S.DeduceReturnType(FunDecl, SourceExpr->getLocStart(), Complain))
+ return false;
+
QualType ResultTy;
if (Context.hasSameUnqualifiedType(TargetFunctionType,
FunDecl->getType()) ||
@@ -9439,6 +9454,11 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
if (FoundResult) *FoundResult = I.getPair();
}
+ if (Matched && getLangOpts().CPlusPlus1y &&
+ Matched->getResultType()->isUndeducedType() &&
+ DeduceReturnType(Matched, ovl->getExprLoc(), Complain))
+ return 0;
+
return Matched;
}
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 16cc43a27f..248665ac86 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -2482,12 +2482,80 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
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 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
} 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 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
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 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
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);
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index bbe34d865b..8efc7a0263 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -2804,21 +2804,25 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
/// Gets the type of a function for template-argument-deducton
/// purposes when it's considered as part of an overload set.
-static QualType GetTypeOfFunction(ASTContext &Context,
- const OverloadExpr::FindResult &R,
+static QualType GetTypeOfFunction(Sema &S, const OverloadExpr::FindResult &R,
FunctionDecl *Fn) {
+ // We may need to deduce the return type of the function now.
+ if (S.getLangOpts().CPlusPlus1y && Fn->getResultType()->isUndeducedType() &&
+ S.DeduceReturnType(Fn, R.Expression->getExprLoc(), /*Diagnose*/false))
+ return QualType();
+
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn))
if (Method->isInstance()) {
// An instance method that's referenced in a form that doesn't
// look like a member pointer is just invalid.
if (!R.HasFormOfMemberPointer) return QualType();
- return Context.getMemberPointerType(Fn->getType(),
- Context.getTypeDeclType(Method->getParent()).getTypePtr());
+ return S.Context.getMemberPointerType(Fn->getType(),
+ S.Context.getTypeDeclType(Method->getParent()).getTypePtr());
}
if (!R.IsAddressOfOperand) return Fn->getType();
- return Context.getPointerType(Fn->getType());
+ return S.Context.getPointerType(Fn->getType());
}
/// Apply the deduction rules for overload sets.
@@ -2852,7 +2856,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
// But we can still look for an explicit specialization.
if (FunctionDecl *ExplicitSpec
= S.ResolveSingleFunctionTemplateSpecialization(Ovl))
- return GetTypeOfFunction(S.Context, R, ExplicitSpec);
+ return GetTypeOfFunction(S, R, ExplicitSpec);
}
return QualType();
@@ -2885,7 +2889,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
}
FunctionDecl *Fn = cast<FunctionDecl>(D);
- QualType ArgType = GetTypeOfFunction(S.Context, R, Fn);
+ QualType ArgType = GetTypeOfFunction(S, R, Fn);
if (ArgType.isNull()) continue;
// Function-to-pointer conversion.
@@ -3391,6 +3395,15 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
Deduced.resize(TemplateParams->size());
+ // If the function has a deduced return type, substitute it for a dependent
+ // type so that we treat it as a non-deduced context in what follows.
+ bool HasUndeducedReturnType = false;
+ if (getLangOpts().CPlusPlus1y && InOverloadResolution &&
+ Function->getResultType()->isUndeducedType()) {
+ FunctionType = SubstAutoType(FunctionType, Context.DependentTy);
+ HasUndeducedReturnType = true;
+ }
+
if (!ArgFunctionType.isNull()) {
unsigned TDF = TDF_TopLevelParameterTypeList;
if (InOverloadResolution) TDF |= TDF_InOverloadResolution;
@@ -3408,6 +3421,13 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
Specialization, Info))
return Result;
+ // If the function has a deduced return type, deduce it now, so we can check
+ // that the deduced function type matches the requested type.
+ if (HasUndeducedReturnType &&
+ Specialization->getResultType()->isUndeducedType() &&
+ DeduceReturnType(Specialization, Info.getLocation(), false))
+ return TDK_MiscellaneousDeductionFailure;
+
// If the requested function type does not match the actual type of the
// specialization with respect to arguments of compatible pointer to function
// types, template argument deduction fails.
@@ -3577,7 +3597,7 @@ namespace {
// auto &&lref = lvalue;
// must transform into "rvalue reference to T" not "rvalue reference to
// auto type deduced as T" in order for [temp.deduct.call]p3 to apply.
- if (isa<TemplateTypeParmType>(Replacement)) {
+ if (!Replacement.isNull() && isa<TemplateTypeParmType>(Replacement)) {
QualType Result = Replacement;
TemplateTypeParmTypeLoc NewTL =
TLB.push<TemplateTypeParmTypeLoc>(Result);
@@ -3601,14 +3621,21 @@ namespace {
return E;
}
- QualType Apply(TypeSourceInfo *TSI) {
- if (TypeSourceInfo *Result = TransformType(TSI))
- return Result->getType();
- return QualType();
+ QualType Apply(TypeLoc TL) {
+ // Create some scratch storage for the transformed type locations.
+ // FIXME: We're just going to throw this information away. Don't build it.
+ TypeLocBuilder TLB;
+ TLB.reserve(TL.getFullDataSize());
+ return TransformType(TLB, TL);
}
};
}
+Sema::DeduceAutoResult
+Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result) {
+ return DeduceAutoType(Type->getTypeLoc(), Init, Result);
+}
+
/// \brief Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6)
///
/// \param Type the type pattern using the auto type-specifier.
@@ -3616,7 +3643,7 @@ namespace {
/// \param Result if type deduction was successful, this will be set to the
/// deduced type.
Sema::DeduceAutoResult
-Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result) {
+Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) {
if (Init->getType()->isNonOverloadPlaceholderType()) {
ExprResult NonPlaceholder = CheckPlaceholderExpr(Init);
if (NonPlaceholder.isInvalid())
@@ -3624,15 +3651,16 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result) {
Init = NonPlaceholder.take();
}
- if (Init->isTypeDependent() || Type->getType()->isDependentType()) {
+ if (Init->isTypeDependent() || Type.getType()->isDependentType()) {
Result = SubstituteAutoTransform(*this, Context.DependentTy).Apply(Type);
+ assert(!Result.isNull() && "substituting DependentTy can't fail");
return DAR_Succeeded;
}
// If this is a 'decltype(auto)' specifier, do the decltype dance.
// Since 'decltype(auto)' can only occur at the top of the type, we
// don't need to go digging for it.
- if (const AutoType *AT = Type->getType()->getAs<AutoType>()) {
+ if (const AutoType *AT = Type.getType()->getAs<AutoType>()) {
if (AT->isDecltypeAuto()) {
if (isa<InitListExpr>(Init)) {
Diag(Init->getLocStart(), diag::err_decltype_auto_initializer_list);
@@ -3643,6 +3671,8 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result) {
// FIXME: Support a non-canonical deduced type for 'auto'.
Deduced = Context.getCanonicalType(Deduced);
Result = SubstituteAutoTransform(*this, Deduced).Apply(Type);
+ if (Result.isNull())
+ return DAR_FailedAlreadyDiagnosed;
return DAR_Succeeded;
}
}
@@ -3704,6 +3734,8 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result) {
}
Result = SubstituteAutoTransform(*this, DeducedType).Apply(Type);
+ if (Result.isNull())
+ return DAR_FailedAlreadyDiagnosed;
// Check that the deduced argument type is compatible with the original
// argument type per C++ [temp.deduct.call]p4.
@@ -3733,6 +3765,22 @@ void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {
<< Init->getSourceRange();
}
+bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
+ bool Diagnose) {
+ assert(FD->getResultType()->isUndeducedType());
+
+ if (FD->getTemplateInstantiationPattern())
+ InstantiateFunctionDefinition(Loc, FD);
+
+ bool StillUndeduced = FD->getResultType()->isUndeducedType();
+ if (StillUndeduced && Diagnose && !FD->isInvalidDecl()) {
+ Diag(Loc, diag::err_auto_fn_used_before_defined) << FD;
+ Diag(FD->getLocation(), diag::note_callee_decl) << FD;
+ }
+
+ return StillUndeduced;
+}
+
static void
MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
bool OnlyDeduced,
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index ee471696bd..688a7360ad 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2868,13 +2868,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
return;
}
- // C++0x [temp.explicit]p9:
- // Except for inline functions, other explicit instantiation declarations
- // have the effect of suppressing the implicit instantiation of the entity
- // to which they refer.
+ // C++1y [temp.explicit]p10:
+ // Except for inline functions, declarations with types deduced from their
+ // initializer or return value, and class template specializations, other
+ // explicit instantiation declarations have the effect of suppressing the
+ // implicit instantiation of the entity to which they refer.
if (Function->getTemplateSpecializationKind()
== TSK_ExplicitInstantiationDeclaration &&
- !PatternDecl->isInlined())
+ !PatternDecl->isInlined() &&
+ !PatternDecl->getResultType()->isUndeducedType())
return;
if (PatternDecl->isInlined())
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 4bf15f0360..0959f7d66a 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -2018,6 +2018,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// The TagDecl owned by the DeclSpec.
TagDecl *OwnedTagDecl = 0;
+ bool ContainsPlaceholderType = false;
+
switch (D.getName().getKind()) {
case UnqualifiedId::IK_ImplicitSelfParam:
case UnqualifiedId::IK_OperatorFunctionId:
@@ -2025,6 +2027,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case UnqualifiedId::IK_LiteralOperatorId:
case UnqualifiedId::IK_TemplateId:
T = ConvertDeclSpecToType(state);
+ ContainsPlaceholderType = D.getDeclSpec().containsPlaceholderType();
if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) {
OwnedTagDecl = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
@@ -2048,6 +2051,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// converts to.
T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId,
&ReturnTypeInfo);
+ ContainsPlaceholderType = T->getContainedAutoType();
break;
}
@@ -2058,7 +2062,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// In C++11, a function declarator using 'auto' must have a trailing return
// type (this is checked later) and we can skip this. In other languages
// using auto, we need to check regardless.
- if (D.getDeclSpec().containsPlaceholderType() &&
+ if (ContainsPlaceholderType &&
(!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) {
int Error = -1;
@@ -2101,10 +2105,12 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
Error = 10; // Type alias
break;
case Declarator::TrailingReturnContext:
- Error = 11; // Function return type
+ if (!SemaRef.getLangOpts().CPlusPlus1y)
+ Error = 11; // Function return type
break;
case Declarator::ConversionIdContext:
- Error = 12; // conversion-type-id
+ if (!SemaRef.getLangOpts().CPlusPlus1y)
+ Error = 12; // conversion-type-id
break;
case Declarator::TypeNameContext:
Error = 13; // Generic
@@ -2599,7 +2605,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// trailing-return-type is only required if we're declaring a function,
// and not, for instance, a pointer to a function.
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
- !FTI.hasTrailingReturnType() && chunkIndex == 0) {
+ !FTI.hasTrailingReturnType() && chunkIndex == 0 &&
+ !S.getLangOpts().CPlusPlus1y) {
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_auto_missing_trailing_return);
T = Context.IntTy;
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp
index 7245b9b47f..39c547b9ae 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y -DCXX1Y
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wno-c++1y-extensions
// FIXME: This is in p11 (?) in C++1y.
@@ -41,3 +41,34 @@ void i() {
decltype(auto) x = 5;
decltype(auto) int r; // expected-error {{cannot combine with previous 'decltype(auto)' declaration specifier}} expected-error {{requires an initializer}}
}
+
+namespace p3_example {
+ template<typename T, typename U> struct is_same_impl {
+ static const bool value = false;
+ };
+ template<typename T> struct is_same_impl<T, T> {
+ static const bool value = true;
+ };
+ template<typename T, typename U> constexpr bool is_same() {
+ return is_same_impl<T,U>::value;
+ }
+
+ auto x = 5;
+ const auto *v = &x, u = 6;
+ static auto y = 0.0;
+ auto int r; // expected-warning {{storage class}} expected-error {{file-scope}}
+
+ static_assert(is_same<decltype(x), int>(), "");
+ static_assert(is_same<decltype(v), const int*>(), "");
+ static_assert(is_same<decltype(u), const int>(), "");
+ static_assert(is_same<decltype(y), double>(), "");
+
+#ifdef CXX1Y
+ auto f() -> int;
+ auto g() { return 0.0; }
+ auto h();
+
+ static_assert(is_same<decltype(f), int()>(), "");
+ static_assert(is_same<decltype(g), double()>(), "");
+#endif
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6-1y.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6-1y.cpp
index 25b5f1984c..66085eda3d 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6-1y.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6-1y.cpp
@@ -64,3 +64,34 @@ decltype(auto) *v4 = { 0 }; // expected-error {{cannot form pointer to 'decltype
auto multi1a = 0, &multi1b = multi1a;
auto multi1c = multi1a, multi1d = multi1b;
decltype(auto) multi1e = multi1a, multi1f = multi1b; // expected-error {{'decltype(auto)' deduced as 'int' in declaration of 'multi1e' and deduced as 'int &' in declaration of 'multi1f'}}
+
+auto f1a() { return 0; }
+decltype(auto) f1d() { return 0; }
+using Int = decltype(f1a());
+using Int = decltype(f1d());
+
+auto f2a(int n) { return n; }
+decltype(auto) f2d(int n) { return n; }
+using Int = decltype(f2a(0));
+using Int = decltype(f2d(0));
+
+auto f3a(int n) { return (n); }
+decltype(auto) f3d(int n) { return (n); } // expected-warning {{reference to stack memory}}
+using Int = decltype(f3a(0));
+using IntLRef = decltype(f3d(0));
+
+auto f4a(int n) { return f(); }
+decltype(auto) f4d(int n) { return f(); }
+using Int = decltype(f4a(0));
+using IntRRef = decltype(f4d(0));
+
+auto f5aa(int n) { auto x = f(); return x; }
+auto f5ad(int n) { decltype(auto) x = f(); return x; }
+decltype(auto) f5da(int n) { auto x = f(); return x; }
+decltype(auto) f5dd(int n) { decltype(auto) x = f(); return x; } // expected-error {{rvalue reference to type 'int' cannot bind to lvalue}}
+using Int = decltype(f5aa(0));
+using Int = decltype(f5ad(0));
+using Int = decltype(f5da(0));
+
+auto init_list_1() { return { 1, 2, 3 }; } // expected-error {{cannot deduce return type from initializer list}}
+decltype(auto) init_list_2() { return { 1, 2, 3 }; } // expected-error {{cannot deduce return type from initializer list}}
diff --git a/test/SemaCXX/cxx1y-deduced-return-type.cpp b/test/SemaCXX/cxx1y-deduced-return-type.cpp
new file mode 100644
index 0000000000..f0146f88d6
--- /dev/null
+++ b/test/SemaCXX/cxx1y-deduced-return-type.cpp
@@ -0,0 +1,338 @@
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s
+
+auto f(); // expected-note {{previous}}
+int f(); // expected-error {{differ only in their return type}}
+
+auto &g();
+auto g() -> auto &;
+
+auto h() -> auto *;
+auto *h();
+
+struct Conv1 {
+ operator auto(); // expected-note {{declared here}}
+} conv1;
+int conv1a = conv1; // expected-error {{function 'operator auto' with deduced return type cannot be used before it is defined}}
+// expected-error@-1 {{no viable conversion}}
+Conv1::operator auto() { return 123; }
+int conv1b = conv1;
+int conv1c = conv1.operator auto();
+int conv1d = conv1.operator int(); // expected-error {{no member named 'operator int'}}
+
+struct Conv2 {
+ operator auto() { return 0; } // expected-note 2{{previous}}
+ operator auto() { return 0.; } // expected-error {{cannot be redeclared}} expected-error {{redefinition of 'operator auto'}}
+};
+
+struct Conv3 {
+ operator auto() { int *p = nullptr; return p; } // expected-note {{candidate}}
+ operator auto*() { int *p = nullptr; return p; } // expected-note {{candidate}}
+} conv3;
+int *conv3a = conv3; // expected-error {{ambiguous}}
+int *conv3b = conv3.operator auto();
+int *conv3c = conv3.operator auto*();
+
+template<typename T>
+struct Conv4 {
+ operator auto() { return T(); }
+};
+Conv4<int> conv4int;
+int conv4a = conv4int;
+int conv4b = conv4int.operator auto();
+
+auto a();
+auto a() { return 0; }
+using T = decltype(a());
+using T = int;
+auto a(); // expected-note {{previous}}
+using T = decltype(a());
+auto *a(); // expected-error {{differ only in their return type}}
+
+auto b(bool k) {
+ if (k)
+ return "hello";
+ return "goodbye";
+}
+
+auto *ptr_1() {
+ return 100; // expected-error {{cannot deduce return type 'auto *' from returned value of type 'int'}}
+}
+
+const auto &ref_1() {
+ return 0; // expected-warning {{returning reference to local temporary}}
+}
+
+auto init_list() {
+ return { 1, 2, 3 }; // expected-error {{cannot deduce return type from initializer list}}
+}
+
+auto fwd_decl(); // expected-note 2{{here}}
+
+int n = fwd_decl(); // expected-error {{function 'fwd_decl' with deduced return type cannot be used before it is defined}}
+int k = sizeof(fwd_decl()); // expected-error {{used before it is defined}}
+
+auto fac(int n) {
+ if (n <= 2)
+ return n;
+ return n * fac(n-1); // ok
+}
+
+auto fac_2(int n) { // expected-note {{declared here}}
+ if (n > 2)
+ return n * fac_2(n-1); // expected-error {{cannot be used before it is defined}}
+ return n;
+}
+
+auto void_ret() {}
+using Void = void;
+using Void = decltype(void_ret());
+
+auto &void_ret_2() {} // expected-error {{cannot deduce return type 'auto &' for function with no return statements}}
+const auto void_ret_3() {} // ok, return type 'const void' is adjusted to 'void'
+
+const auto void_ret_4() {
+ if (false)
+ return void();
+ if (false)
+ return;
+ return 0; // expected-error {{'auto' in return type deduced as 'int' here but deduced as 'void' in earlier return statement}}
+}
+
+namespace Templates {
+ template<typename T> auto f1() {
+ return T() + 1;
+ }
+ template<typename T> auto &f2(T &&v) { return v; }
+ int a = f1<int>();
+ const int &b = f2(0);
+ double d;
+ float &c = f2(0.0); // expected-error {{non-const lvalue reference to type 'float' cannot bind to a value of unrelated type 'double'}}
+
+ template<typename T> auto fwd_decl(); // expected-note {{declared here}}
+ int e = fwd_decl<int>(); // expected-error {{cannot be used before it is defined}}
+ template<typename T> auto fwd_decl() { return 0; }
+ int f = fwd_decl<int>();
+ template<typename T> auto fwd_decl();
+ int g = fwd_decl<char>();
+
+ auto (*p)() = f1; // expected-error {{incompatible initializer}}
+ auto (*q)() = f1<int>; // ok
+
+ typedef decltype(f2(1.2)) dbl; // expected-note {{previous}}
+ typedef float dbl; // expected-error {{typedef redefinition with different types ('float' vs 'decltype(f2(1.2))' (aka 'double &'))}}
+
+ extern template auto fwd_decl<double>();
+ int k1 = fwd_decl<double>();
+ extern template int fwd_decl<char>(); // expected-error {{does not refer to a function template}}
+ int k2 = fwd_decl<char>();
+
+ template<typename T> auto instantiate() { T::error; } // expected-error {{has no members}}
+ extern template auto instantiate<int>(); // ok
+ int k = instantiate<int>(); // expected-note {{in instantiation of}}
+ template<> auto instantiate<char>() {} // ok
+ template<> void instantiate<double>() {} // expected-error {{no function template matches}}
+
+ template<typename T> auto arg_single() { return 0; }
+ template<typename T> auto arg_multi() { return 0l; }
+ template<typename T> auto arg_multi(int) { return "bad"; }
+ template<typename T> struct Outer {
+ static auto arg_single() { return 0.f; }
+ static auto arg_multi() { return 0.; }
+ static auto arg_multi(int) { return "bad"; }
+ };
+ template<typename T> T &take_fn(T (*p)());
+
+ int &check1 = take_fn(arg_single); // expected-error {{no matching}} expected-note@-2 {{couldn't infer}}
+ int &check2 = take_fn(arg_single<int>);
+ int &check3 = take_fn<int>(arg_single); // expected-error {{no matching}} expected-note@-4{{no overload of 'arg_single'}}
+ int &check4 = take_fn<int>(arg_single<int>);
+ long &check5 = take_fn(arg_multi); // expected-error {{no matching}} expected-note@-6 {{couldn't infer}}
+ long &check6 = take_fn(arg_multi<int>);
+ long &check7 = take_fn<long>(arg_multi); // expected-error {{no matching}} expected-note@-8{{no overload of 'arg_multi'}}
+ long &check8 = take_fn<long>(arg_multi<int>);
+
+ float &mem_check1 = take_fn(Outer<int>::arg_single);
+ float &mem_check2 = take_fn<float>(Outer<char>::arg_single);
+ double &mem_check3 = take_fn(Outer<long>::arg_multi);
+ double &mem_check4 = take_fn<double>(Outer<double>::arg_multi);
+
+ namespace Deduce1 {
+ template<typename T> auto f() { return 0; } // expected-note {{candidate}}
+ template<typename T> void g(T(*)()); // expected-note 2{{candidate}}
+ void h() {
+ auto p = f<int>;
+ auto (*q)() = f<int>;
+ int (*r)() = f; // expected-error {{does not match}}
+ g(f<int>);
+ g<int>(f); // expected-error {{no matching function}}
+ g(f); // expected-error {{no matching function}}
+ }
+ }
+
+ namespace Deduce2 {
+ template<typename T> auto f(int) { return 0; } // expected-note {{candidate}}
+ template<typename T> void g(T(*)(int)); // expected-note 2{{candidate}}
+ void h() {
+ auto p = f<int>;
+ auto (*q)(int) = f<int>;
+ int (*r)(int) = f; // expected-error {{does not match}}
+ g(f<int>);
+ g<int>(f); // expected-error {{no matching function}}
+ g(f); // expected-error {{no matching function}}
+ }
+ }
+
+ namespace Deduce3 {
+ template<typename T> auto f(T) { return 0; }
+ template<typename T> void g(T(*)(int)); // expected-note {{couldn't infer}}
+ void h() {
+ auto p = f<int>;
+ auto (*q)(int) = f<int>;
+ int (*r)(int) = f; // ok
+ g(f<int>);
+ g<int>(f); // ok
+ g(f); // expected-error {{no matching function}}
+ }
+ }
+
+ namespace DeduceInDeducedReturnType {
+ template<typename T, typename U> auto f() -> auto (T::*)(U) {
+ int (T::*result)(U) = nullptr;
+ return result;
+ }
+ struct S {};
+ int (S::*(*p)())(double) = f;
+ int (S::*(*q)())(double) = f<S, double>;
+ }
+}
+
+auto fwd_decl_using();
+namespace N { using ::fwd_decl_using; }
+auto fwd_decl_using() { return 0; }
+namespace N { int k = N::fwd_decl_using(); }
+
+namespace OverloadResolutionNonTemplate {
+ auto f();
+ auto f(int); // expected-note {{here}}
+
+ int &g(int (*f)()); // expected-note {{not viable: no overload of 'f' matching 'int (*)()'}}
+ char &g(int (*f)(int)); // expected-note {{not viable: no overload of 'f' matching 'int (*)(int)'}}
+
+ int a = g(f); // expected-error {{no matching function}}
+
+ auto f() { return 0; }
+
+ // FIXME: It's not completely clear whether this should be ill-formed.
+ int &b = g(f); // expected-error {{used before it is defined}}
+
+ auto f(int) { return 0.0; }
+
+ int &c = g(f); // ok
+}
+
+namespace OverloadResolutionTemplate {
+ auto f();
+ template<typename T> auto f(T);
+
+ int &g(int (*f)()); // expected-note {{not viable: no overload of 'f' matching 'int (*)()'}} expected-note {{candidate}}
+ char &g(int (*f)(int)); // expected-note {{not viable: no overload of 'f' matching 'int (*)(int)'}} expected-note {{candidate}}
+
+ int a = g(f); // expected-error {{no matching function}}
+
+ auto f() { return 0; }
+
+ int &b = g(f); // ok (presumably), due to deduction failure forming type of 'f<int>'
+
+ template<typename T> auto f(T) { return 0; }
+
+ int &c = g(f); // expected-error {{ambiguous}}
+}
+
+namespace DefaultedMethods {
+ struct A {
+ auto operator=(const A&) = default; // expected-error {{must return 'DefaultedMethods::A &'}}
+ A &operator=(A&&); // expected-note {{previous}}
+ };
+ auto A::operator=(A&&) = default; // expected-error {{differs from the declaration in the return type}}
+}
+
+namespace Constexpr {
+ constexpr auto f1(int n) { return n; }
+ struct NonLiteral { ~NonLiteral(); } nl; // expected-note {{user-provided destructor}}
+ constexpr auto f2(int n) { return nl; } // expected-error {{return type 'Constexpr::NonLiteral' is not a literal type}}
+}
+
+// It's not really clear whether these are valid, but this matches g++.
+using size_t = decltype(sizeof(0));
+auto operator new(size_t n, const char*); // expected-error {{must return type 'void *'}}
+auto operator delete(void *, const char*); // expected-error {{must return type 'void'}}
+
+namespace Virtual {
+ struct S {
+ virtual auto f() { return 0; } // expected-error {{function with deduced return type cannot be virtual}} expected-note {{here}}
+ };
+ // Allow 'auto' anyway for error recovery.
+ struct T : S {
+ int f();
+ };
+ struct U : S {
+ auto f(); // expected-error {{different return}}
+ };
+
+ // And here's why...
+ struct V { virtual auto f(); }; // expected-error {{cannot be virtual}}
+ struct W : V { virtual auto f(); }; // expected-error {{cannot be virtual}}
+ auto V::f() { return 0; } // in tu1.cpp
+ auto W::f() { return 0.0; } // in tu2.cpp
+ W w;
+ int k1 = w.f();
+ int k2 = ((V&)w).f();
+}
+
+namespace std_examples {
+
+namespace NoReturn {
+ auto f() {}
+ void (*p)() = &f;
+
+ auto *g() {} // expected-error {{cannot deduce return type 'auto *' for function with no return statements}}
+}
+
+namespace UseBeforeComplete {
+ auto n = n; // expected-error {{variable 'n' declared with 'auto' type cannot appear in its own initializer}}
+ auto f(); // expected-note {{declared here}}
+ void g() { &f; } // expected-error {{function 'f' with deduced return type cannot be used before it is defined}}
+ auto sum(int i) {
+ if (i == 1)
+ return i;
+ else
+ return sum(i - 1) + i;
+ }
+}
+
+namespace Redecl {
+ auto f();
+ auto f() { return 42; }
+ auto f(); // expected-note 2{{previous}}
+ int f(); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+ decltype(auto) f(); // expected-error {{cannot be overloaded}}
+
+ template<typename T> auto g(T t) { return t; } // expected-note {{candidate}}
+ template auto g(int);
+ template char g(char); // expected-error {{does not refer to a function}}
+ template<> auto g(double);
+
+ template<typename T> T g(T t) { return t; } // expected-note {{candidate}}
+ template char g(char);
+ template auto g(float);
+
+ void h() { return g(42); } // expected-error {{ambiguous}}
+}
+
+namespace ExplicitInstantiationDecl {
+ template<typename T> auto f(T t) { return t; }
+ extern template auto f(int);
+ int (*p)(int) = f;
+}
+
+}
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 08baad4eae..206ea38514 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -431,7 +431,7 @@ ISO/IEC JTC1/SC22/WG21 post-Bristol mailing ships.</p>
</tr>
<tr>
<td>Return type deduction for normal functions</td>
- <td class="none" align="center">No</td>
+ <td class="none" align="center">Partial</td>
</tr>
<tr>
<td>Runtime-sized arrays with automatic storage duration</td>