PR31846: Don't replace 'auto' type with a template parameter type in a generic lambda

until after we've checked whether 'auto' is valid in the current language mode.

llvm-svn: 294078
This commit is contained in:
Richard Smith 2017-02-04 01:28:01 +00:00
parent 56ca3a9ad9
commit 33c33c3e86
4 changed files with 44 additions and 34 deletions

View File

@ -6727,6 +6727,9 @@ public:
/// \brief Substitute Replacement for auto in TypeWithAuto
TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
QualType Replacement);
/// \brief Completely replace the \c auto in \p TypeWithAuto by
/// \p Replacement. This does not retain any \c auto type sugar.
QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement);
/// \brief Result type of DeduceAutoType.
enum DeduceAutoResult {

View File

@ -4250,6 +4250,13 @@ TypeSourceInfo* Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
.TransformType(TypeWithAuto);
}
QualType Sema::ReplaceAutoType(QualType TypeWithAuto,
QualType TypeToReplaceAuto) {
return SubstituteAutoTransform(*this, TypeToReplaceAuto,
/*UseAutoSugar*/ false)
.TransformType(TypeWithAuto);
}
void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {
if (isa<InitListExpr>(Init))
Diag(VDecl->getLocation(),

View File

@ -1502,40 +1502,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
case DeclSpec::TST_auto:
// TypeQuals handled by caller.
// If auto is mentioned in a lambda parameter context, convert it to a
// template parameter type immediately, with the appropriate depth and
// index, and update sema's state (LambdaScopeInfo) for the current lambda
// being analyzed (which tracks the invented type template parameter).
if (declarator.getContext() == Declarator::LambdaExprParameterContext) {
sema::LambdaScopeInfo *LSI = S.getCurLambda();
assert(LSI && "No LambdaScopeInfo on the stack!");
const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size();
const bool IsParameterPack = declarator.hasEllipsis();
// Turns out we must create the TemplateTypeParmDecl here to
// retrieve the corresponding template parameter type.
TemplateTypeParmDecl *CorrespondingTemplateParam =
TemplateTypeParmDecl::Create(Context,
// Temporarily add to the TranslationUnit DeclContext. When the
// associated TemplateParameterList is attached to a template
// declaration (such as FunctionTemplateDecl), the DeclContext
// for each template parameter gets updated appropriately via
// a call to AdoptTemplateParameterList.
Context.getTranslationUnitDecl(),
/*KeyLoc*/ SourceLocation(),
/*NameLoc*/ declarator.getLocStart(),
TemplateParameterDepth,
AutoParameterPosition, // our template param index
/* Identifier*/ nullptr, false, IsParameterPack);
LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam);
// Replace the 'auto' in the function parameter with this invented
// template type parameter.
Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0);
} else {
Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);
}
Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);
break;
case DeclSpec::TST_auto_type:
@ -2802,6 +2769,32 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
if (!SemaRef.getLangOpts().CPlusPlus14 ||
!Auto || Auto->getKeyword() != AutoTypeKeyword::Auto)
Error = 16;
else {
// If auto is mentioned in a lambda parameter context, convert it to a
// template parameter type.
sema::LambdaScopeInfo *LSI = SemaRef.getCurLambda();
assert(LSI && "No LambdaScopeInfo on the stack!");
const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size();
const bool IsParameterPack = D.hasEllipsis();
// Create the TemplateTypeParmDecl here to retrieve the corresponding
// template parameter type. Template parameters are temporarily added
// to the TU until the associated TemplateDecl is created.
TemplateTypeParmDecl *CorrespondingTemplateParam =
TemplateTypeParmDecl::Create(
SemaRef.Context, SemaRef.Context.getTranslationUnitDecl(),
/*KeyLoc*/SourceLocation(), /*NameLoc*/D.getLocStart(),
TemplateParameterDepth, AutoParameterPosition,
/*Identifier*/nullptr, false, IsParameterPack);
LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam);
// Replace the 'auto' in the function parameter with this invented
// template type parameter.
// FIXME: Retain some type sugar to indicate that this was written
// as 'auto'.
T = SemaRef.ReplaceAutoType(
T, QualType(CorrespondingTemplateParam->getTypeForDecl(), 0));
}
break;
case Declarator::MemberContext: {
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||

View File

@ -8,3 +8,10 @@ void f() {
typedef auto PR25449(); // expected-error {{'auto' not allowed in typedef}}
thread_local auto x; // expected-error {{requires an initializer}}
void g() {
[](auto){}(0);
#if __cplusplus == 201103L
// expected-error@-2 {{'auto' not allowed in lambda parameter}}
#endif
}