PR16875: The return type of a dependent function type is visible when it's
referenced as a member of the current instantiation. In that case, deduce the
type of the function to a dependent type rather than exposing an undeduced auto
type to the rest of the current instantiation.
The standard doesn't really say that the type is dependent in this case; I'll
bring this up with CWG.
llvm-svn: 188410
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index c583674..9d4280a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2459,7 +2459,7 @@
// cannot be overloaded.
// Go back to the type source info to compare the declared return types,
- // per C++1y [dcl.type.auto]p??:
+ // per C++1y [dcl.type.auto]p13:
// 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.
@@ -2494,9 +2494,14 @@
// 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()));
+ New->setType(
+ SubstAutoType(New->getType(),
+ OldAT->isDependentType() ? Context.DependentTy
+ : OldAT->getDeducedType()));
NewQType = Context.getCanonicalType(
- SubstAutoType(NewQType, OldAT->getDeducedType()));
+ SubstAutoType(NewQType,
+ OldAT->isDependentType() ? Context.DependentTy
+ : OldAT->getDeducedType()));
}
}
@@ -6688,6 +6693,20 @@
Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_auto_fn_virtual);
}
+ if (getLangOpts().CPlusPlus1y && NewFD->isDependentContext() &&
+ NewFD->getResultType()->isUndeducedType()) {
+ // If the function template is referenced directly (for instance, as a
+ // member of the current instantiation), pretend it has a dependent type.
+ // This is not really justified by the standard, but is the only sane
+ // thing to do.
+ const FunctionProtoType *FPT =
+ NewFD->getType()->castAs<FunctionProtoType>();
+ QualType Result = SubstAutoType(FPT->getResultType(),
+ Context.DependentTy);
+ NewFD->setType(Context.getFunctionType(Result, FPT->getArgTypes(),
+ FPT->getExtProtoInfo()));
+ }
+
// C++ [dcl.fct.spec]p3:
// The inline specifier shall not appear on a block scope function
// declaration.
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 46e350b..87e7e03 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2611,7 +2611,21 @@
IgnoreParens().castAs<FunctionProtoTypeLoc>().getResultLoc();
QualType Deduced;
- if (RetExpr) {
+ if (RetExpr && isa<InitListExpr>(RetExpr)) {
+ // If the deduction is for a return statement and the initializer is
+ // a braced-init-list, the program is ill-formed.
+ Diag(RetExpr->getExprLoc(), diag::err_auto_fn_return_init_list);
+ return true;
+ }
+
+ if (FD->isDependentContext()) {
+ // C++1y [dcl.spec.auto]p12:
+ // Return type deduction [...] occurs when the definition is
+ // instantiated even if the function body contains a return
+ // statement with a non-type-dependent operand.
+ assert(AT->isDeduced() && "should have deduced to dependent type");
+ return false;
+ } else 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)) {
@@ -2652,7 +2666,8 @@
// the program is ill-formed.
if (AT->isDeduced() && !FD->isInvalidDecl()) {
AutoType *NewAT = Deduced->getContainedAutoType();
- if (!Context.hasSameType(AT->getDeducedType(), NewAT->getDeducedType())) {
+ if (!FD->isDependentContext() &&
+ !Context.hasSameType(AT->getDeducedType(), NewAT->getDeducedType())) {
Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
<< (AT->isDecltypeAuto() ? 1 : 0)
<< NewAT->getDeducedType() << AT->getDeducedType();
@@ -2696,13 +2711,10 @@
// 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)) {
+ if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) {
FD->setInvalidDecl();
return StmtError();
} else {
@@ -2711,6 +2723,8 @@
}
}
+ bool HasDependentReturnType = FnRetType->isDependentType();
+
ReturnStmt *Result = 0;
if (FnRetType->isVoidType()) {
if (RetValExp) {
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 898ced2..c8669ae 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2581,7 +2581,6 @@
}
// Instantiate the return type.
- // FIXME: exception-specifications?
QualType ResultType;
{
// C++11 [expr.prim.general]p3:
@@ -3555,11 +3554,11 @@
// 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;
+ bool HasDeducedReturnType = false;
if (getLangOpts().CPlusPlus1y && InOverloadResolution &&
- Function->getResultType()->isUndeducedType()) {
+ Function->getResultType()->getContainedAutoType()) {
FunctionType = SubstAutoType(FunctionType, Context.DependentTy);
- HasUndeducedReturnType = true;
+ HasDeducedReturnType = true;
}
if (!ArgFunctionType.isNull()) {
@@ -3581,7 +3580,7 @@
// 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 &&
+ if (HasDeducedReturnType &&
Specialization->getResultType()->isUndeducedType() &&
DeduceReturnType(Specialization, Info.getLocation(), false))
return TDK_MiscellaneousDeductionFailure;
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 3379ebc..3cb20c7 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3161,7 +3161,7 @@
if (Function->getTemplateSpecializationKind()
== TSK_ExplicitInstantiationDeclaration &&
!PatternDecl->isInlined() &&
- !PatternDecl->getResultType()->isUndeducedType())
+ !PatternDecl->getResultType()->getContainedAutoType())
return;
if (PatternDecl->isInlined())