diff options
-rw-r--r-- | include/clang/AST/ASTContext.h | 3 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 17 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 8 | ||||
-rw-r--r-- | include/clang/Sema/TemplateDeduction.h | 4 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 38 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 56 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 20 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 91 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 78 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 15 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp | 33 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6-1y.cpp | 31 | ||||
-rw-r--r-- | test/SemaCXX/cxx1y-deduced-return-type.cpp | 338 | ||||
-rw-r--r-- | www/cxx_status.html | 2 |
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> |