From a085da86242c9b8e3466f8cf6f4397e9f248fd20 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 17 Mar 2011 16:11:59 +0000 Subject: [PATCH] Fix PR9488: 'auto' type substitution can fail (for instance, if it creates a reference-to-void type). Don't crash if it does. Also fix an issue where type source information for the resulting type was being lost. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127811 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 3 ++- lib/Sema/SemaDecl.cpp | 8 +++++--- lib/Sema/SemaDeclCXX.cpp | 8 +++++--- lib/Sema/SemaExprCXX.cpp | 10 ++++++---- lib/Sema/SemaTemplateDeduction.cpp | 11 ++++++++--- test/SemaCXX/auto-subst-failure.cpp | 15 +++++++++++++++ 6 files changed, 41 insertions(+), 14 deletions(-) create mode 100644 test/SemaCXX/auto-subst-failure.cpp diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 394a57ae25..043722b29c 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3879,7 +3879,8 @@ public: FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info); - bool DeduceAutoType(QualType AutoType, Expr *Initializer, QualType &Result); + bool DeduceAutoType(TypeSourceInfo *AutoType, Expr *Initializer, + TypeSourceInfo *&Result); FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a10b32513d..540c4e0bf0 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4664,15 +4664,17 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) { - QualType DeducedType; - if (!DeduceAutoType(VDecl->getType(), Init, DeducedType)) { + TypeSourceInfo *DeducedType = 0; + if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType)) Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure) << VDecl->getDeclName() << VDecl->getType() << Init->getType() << Init->getSourceRange(); + if (!DeducedType) { RealDecl->setInvalidDecl(); return; } - VDecl->setType(DeducedType); + VDecl->setTypeSourceInfo(DeducedType); + VDecl->setType(DeducedType->getType()); // If this is a redeclaration, check that the type we just deduced matches // the previously declared type. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 04c21bc47c..430f9c8052 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -6137,15 +6137,17 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, } Expr *Init = Exprs.get()[0]; - QualType DeducedType; - if (!DeduceAutoType(VDecl->getType(), Init, DeducedType)) { + TypeSourceInfo *DeducedType = 0; + if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType)) Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure) << VDecl->getDeclName() << VDecl->getType() << Init->getType() << Init->getSourceRange(); + if (!DeducedType) { RealDecl->setInvalidDecl(); return; } - VDecl->setType(DeducedType); + VDecl->setTypeSourceInfo(DeducedType); + VDecl->setType(DeducedType->getType()); // If this is a redeclaration, check that the type we just deduced matches // the previously declared type. diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 9955b0378b..8ceeff9536 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -848,16 +848,18 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, diag::err_auto_new_ctor_multiple_expressions) << AllocType << TypeRange); } - QualType DeducedType; - if (!DeduceAutoType(AllocType, ConstructorArgs.get()[0], DeducedType)) + TypeSourceInfo *DeducedType = 0; + if (!DeduceAutoType(AllocTypeInfo, ConstructorArgs.get()[0], DeducedType)) return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) << AllocType << ConstructorArgs.get()[0]->getType() << TypeRange << ConstructorArgs.get()[0]->getSourceRange()); + if (!DeducedType) + return ExprError(); - AllocType = DeducedType; - AllocTypeInfo = Context.getTrivialTypeSourceInfo(AllocType, StartLoc); + AllocTypeInfo = DeducedType; + AllocType = AllocTypeInfo->getType(); } // Per C++0x [expr.new]p5, the type being constructed may be a diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index c6b4d96d02..202a736f3f 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -3003,11 +3003,14 @@ namespace { /// /// \param Result if type deduction was successful, this will be set to the /// deduced type. This may still contain undeduced autos if the type is -/// dependent. +/// dependent. This will be set to null if deduction succeeded, but auto +/// substitution failed; the appropriate diagnostic will already have been +/// produced in that case. /// /// \returns true if deduction succeeded, false if it failed. bool -Sema::DeduceAutoType(QualType Type, Expr *Init, QualType &Result) { +Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *Init, + TypeSourceInfo *&Result) { if (Init->isTypeDependent()) { Result = Type; return true; @@ -3025,8 +3028,10 @@ Sema::DeduceAutoType(QualType Type, Expr *Init, QualType &Result) { FixedSizeTemplateParameterList<1> TemplateParams(Loc, Loc, &TemplParamPtr, Loc); - QualType FuncParam = + TypeSourceInfo *FuncParamInfo = SubstituteAutoTransform(*this, TemplArg).TransformType(Type); + assert(FuncParamInfo && "substituting template parameter for 'auto' failed"); + QualType FuncParam = FuncParamInfo->getType(); // Deduce type of TemplParam in Func(Init) llvm::SmallVector Deduced; diff --git a/test/SemaCXX/auto-subst-failure.cpp b/test/SemaCXX/auto-subst-failure.cpp new file mode 100644 index 0000000000..442c7e82cc --- /dev/null +++ b/test/SemaCXX/auto-subst-failure.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x + +void f() { + auto a = f(); // expected-error {{variable has incomplete type 'void'}} + auto &b = f(); // expected-error {{cannot form a reference to 'void'}} + auto *c = f(); // expected-error {{incompatible initializer of type 'void'}} + + auto d(f()); // expected-error {{variable has incomplete type 'void'}} + auto &&e(f()); // expected-error {{cannot form a reference to 'void'}} + auto *g(f()); // expected-error {{incompatible initializer of type 'void'}} + + (void)new auto(f()); // expected-error {{allocation of incomplete type 'void'}} + (void)new auto&(f()); // expected-error {{cannot form a reference to 'void'}} + (void)new auto*(f()); // expected-error {{incompatible constructor argument of type 'void'}} +}