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;
+ };<