PR13293: Defer deduction of an auto type with a dependent declarator, such as "auto (*f)(T t)".

llvm-svn: 159908
This commit is contained in:
Richard Smith 2012-07-08 04:13:07 +00:00
parent 8a874c93d9
commit 74801c8182
4 changed files with 85 additions and 9 deletions

View File

@ -6335,7 +6335,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init); ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) { AutoType *Auto = 0;
if (TypeMayContainAuto &&
(Auto = VDecl->getType()->getContainedAutoType()) &&
!Auto->isDeduced()) {
Expr *DeduceInit = Init; Expr *DeduceInit = Init;
// Initializer could be a C++ direct-initializer. Deduction only works if it // Initializer could be a C++ direct-initializer. Deduction only works if it
// contains exactly one expression. // contains exactly one expression.

View File

@ -1093,8 +1093,10 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
} }
} }
// C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
if (TypeMayContainAuto && AllocType->getContainedAutoType()) { AutoType *AT = 0;
if (TypeMayContainAuto &&
(AT = AllocType->getContainedAutoType()) && !AT->isDeduced()) {
if (initStyle == CXXNewExpr::NoInit || NumInits == 0) if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg) return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
<< AllocType << TypeRange); << AllocType << TypeRange);
@ -1110,8 +1112,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
} }
Expr *Deduce = Inits[0]; Expr *Deduce = Inits[0];
TypeSourceInfo *DeducedType = 0; TypeSourceInfo *DeducedType = 0;
if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed)
DAR_Failed)
return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
<< AllocType << Deduce->getType() << AllocType << Deduce->getType()
<< TypeRange << Deduce->getSourceRange()); << TypeRange << Deduce->getSourceRange());

View File

@ -3464,6 +3464,41 @@ namespace {
return E; return E;
} }
}; };
/// Determine whether the specified type (which contains an 'auto' type
/// specifier) is dependent. This is not trivial, because the 'auto' specifier
/// itself claims to be type-dependent.
bool isDependentAutoType(QualType Ty) {
while (1) {
QualType Pointee = Ty->getPointeeType();
if (!Pointee.isNull()) {
Ty = Pointee;
} else if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()){
if (MPT->getClass()->isDependentType())
return true;
Ty = MPT->getPointeeType();
} else if (const FunctionProtoType *FPT = Ty->getAs<FunctionProtoType>()){
for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin(),
E = FPT->arg_type_end();
I != E; ++I)
if ((*I)->isDependentType())
return true;
Ty = FPT->getResultType();
} else if (Ty->isDependentSizedArrayType()) {
return true;
} else if (const ArrayType *AT = Ty->getAsArrayTypeUnsafe()) {
Ty = AT->getElementType();
} else if (Ty->getAs<DependentSizedExtVectorType>()) {
return true;
} else if (const VectorType *VT = Ty->getAs<VectorType>()) {
Ty = VT->getElementType();
} else {
break;
}
}
assert(Ty->getAs<AutoType>() && "didn't find 'auto' in auto type");
return false;
}
} }
/// \brief Deduce the type for an auto type-specifier (C++0x [dcl.spec.auto]p6) /// \brief Deduce the type for an auto type-specifier (C++0x [dcl.spec.auto]p6)
@ -3486,7 +3521,7 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
Init = result.take(); Init = result.take();
} }
if (Init->isTypeDependent()) { if (Init->isTypeDependent() || isDependentAutoType(Type->getType())) {
Result = Type; Result = Type;
return DAR_Succeeded; return DAR_Succeeded;
} }

View File

@ -49,3 +49,40 @@ void p3example() {
same<__typeof(u), const int> uHasTypeConstInt; same<__typeof(u), const int> uHasTypeConstInt;
same<__typeof(y), double> yHasTypeDouble; same<__typeof(y), double> yHasTypeDouble;
} }
#if __cplusplus >= 201103L
namespace PR13293 {
// Ensure that dependent declarators have their deduction delayed.
int f(char);
double f(short);
template<typename T> struct S {
static constexpr auto (*p)(T) = &f;
};
constexpr int (*f1)(char) = &f;
constexpr double (*f2)(short) = &f;
static_assert(S<char>::p == f1, "");
static_assert(S<short>::p == f2, "");
struct K { int n; };
template<typename T> struct U {
static constexpr auto (T::*p) = &K::n;
};
static_assert(U<K>::p == &K::n, "");
template<typename T>
using X = auto(int) -> auto(*)(T) -> auto(*)(char) -> long;
X<double> x;
template<typename T> struct V {
//static constexpr auto (*p)(int) -> auto(*)(T) -> auto(*)(char) = &x; // ill-formed
static constexpr auto (*(*(*p)(int))(T))(char) = &x; // ok
};
V<double> v;
int *g(double);
template<typename T> void h() {
new (auto(*)(T)) (&g);
}
template void h<double>();
}
#endif