From 483b9f3bc05c5409e2c6643f1c9d91e21c8ff9d2 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 21 Feb 2011 20:05:19 +0000 Subject: [PATCH] Tweaks to C++0x deduced auto type support: * Flag indicating 'we're parsing this auto typed variable's initializer' moved from VarDecl to Sema * Temporary template parameter list for auto deduction is now allocated on the stack. * Deduced 'auto' types are now uniqued. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126139 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 1 + include/clang/AST/Decl.h | 18 +------------ include/clang/AST/DeclTemplate.h | 17 ++++++++++++ include/clang/Sema/Sema.h | 5 ++++ lib/AST/ASTContext.cpp | 20 ++++++++++---- lib/Parse/ParseDecl.cpp | 2 ++ lib/Parse/ParseExprCXX.cpp | 2 ++ lib/Sema/Sema.cpp | 6 +++++ lib/Sema/SemaDecl.cpp | 27 ++++++++++--------- lib/Sema/SemaDeclCXX.cpp | 4 +-- lib/Sema/SemaExpr.cpp | 10 +++---- lib/Sema/SemaTemplateDeduction.cpp | 14 +++++----- .../dcl.spec/dcl.type/dcl.spec.auto/p3.cpp | 9 ++++++- 13 files changed, 85 insertions(+), 50 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 0e887133d0..43a53d9bcd 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -115,6 +115,7 @@ class ASTContext { llvm::FoldingSet PackExpansionTypes; mutable llvm::FoldingSet ObjCObjectTypes; mutable llvm::FoldingSet ObjCObjectPointerTypes; + mutable llvm::FoldingSet AutoTypes; llvm::FoldingSet AttributedTypes; mutable llvm::FoldingSet QualifiedTemplateNames; diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index ee515da083..80b1ca07b8 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -652,10 +652,6 @@ private: /// slot of its function, enabling the named return value optimization (NRVO). bool NRVOVariable : 1; - /// \brief Whether this variable has a deduced C++0x auto type for which we're - /// currently parsing the initializer. - bool ParsingAutoInit : 1; - friend class StmtIteratorBase; friend class ASTDeclReader; @@ -665,7 +661,7 @@ protected: StorageClass SCAsWritten) : DeclaratorDecl(DK, DC, L, Id, T, TInfo), Init(), ThreadSpecified(false), HasCXXDirectInit(false), - ExceptionVar(false), NRVOVariable(false), ParsingAutoInit(false) { + ExceptionVar(false), NRVOVariable(false) { SClass = SC; SClassAsWritten = SCAsWritten; } @@ -889,18 +885,6 @@ public: void setInit(Expr *I); - /// \brief Check whether we are in the process of parsing an initializer - /// needed to deduce the type of this variable. - bool isParsingAutoInit() const { - return ParsingAutoInit; - } - - /// \brief Note whether we are currently parsing an initializer needed to - /// deduce the type of this variable. - void setParsingAutoInit(bool P) { - ParsingAutoInit = P; - } - EvaluatedStmt *EnsureEvaluatedStmt() const { EvaluatedStmt *Eval = Init.dyn_cast(); if (!Eval) { diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 176c6badae..f41859c857 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -48,6 +48,7 @@ class TemplateParameterList { /// parameter list. unsigned NumParams; +protected: TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc, NamedDecl **Params, unsigned NumParams, SourceLocation RAngleLoc); @@ -107,6 +108,19 @@ public: } }; +/// FixedSizeTemplateParameterList - Stores a list of template parameters for a +/// TemplateDecl and its derived classes. Suitable for creating on the stack. +template +class FixedSizeTemplateParameterList : public TemplateParameterList { + NamedDecl *Params[N]; + +public: + FixedSizeTemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc, + NamedDecl **Params, SourceLocation RAngleLoc) : + TemplateParameterList(TemplateLoc, LAngleLoc, Params, N, RAngleLoc) { + } +}; + /// \brief A template argument list. class TemplateArgumentList { /// \brief The template argument list. @@ -914,6 +928,9 @@ class TemplateTypeParmDecl : public TypeDecl { TypeForDecl = Type.getTypePtrOrNull(); } + /// Sema creates these on the stack during auto type deduction. + friend class Sema; + public: static TemplateTypeParmDecl *Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 91d6914f24..d25c0c3e97 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -267,6 +267,10 @@ public: /// same list more than once. llvm::OwningPtr PureVirtualClassDiagSet; + /// ParsingInitForAutoVars - a set of declarations with auto types for which + /// we are currently parsing the initializer. + llvm::SmallPtrSet ParsingInitForAutoVars; + /// \brief A mapping from external names to the most recent /// locally-scoped external declaration with that name. /// @@ -856,6 +860,7 @@ public: void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto); void ActOnInitializerError(Decl *Dcl); void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc); + void FinalizeDeclaration(Decl *D); DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, Decl **Group, unsigned NumDecls); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 945dfb87f2..df92d11192 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2683,12 +2683,22 @@ QualType ASTContext::getDecltypeType(Expr *e) const { return QualType(dt, 0); } -/// getAutoType - Unlike many "get" functions, we don't unique -/// AutoType AST's. +/// getAutoType - We only unique auto types after they've been deduced. QualType ASTContext::getAutoType(QualType DeducedType) const { - AutoType *at = new (*this, TypeAlignment) AutoType(DeducedType); - Types.push_back(at); - return QualType(at, 0); + void *InsertPos = 0; + if (!DeducedType.isNull()) { + // Look in the folding set for an existing type. + llvm::FoldingSetNodeID ID; + AutoType::Profile(ID, DeducedType); + if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(AT, 0); + } + + AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType); + Types.push_back(AT); + if (InsertPos) + AutoTypes.InsertNode(AT, InsertPos); + return QualType(AT, 0); } /// getTagDeclType - Return the unique reference to the type for the diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 5e3bfe77e7..37d152ed9d 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -667,6 +667,8 @@ Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D, Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsAuto); } + Actions.FinalizeDeclaration(ThisDecl); + return ThisDecl; } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index e73578f23e..2fb9c0e5ae 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -836,6 +836,8 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, // FIXME: Build a reference to this declaration? Convert it to bool? // (This is currently handled by Sema). + + Actions.FinalizeDeclaration(DeclOut); return false; } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 23a3c24804..78d49b7415 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -466,6 +466,12 @@ void Sema::ActOnEndOfTranslationUnit() { checkUndefinedInternals(*this); } + // Check we've noticed that we're no longer parsing the initializer for every + // variable. If we miss cases, then at best we have a performance issue and + // at worst a rejects-valid bug. + assert(ParsingInitForAutoVars.empty() && + "Didn't unmark var as having its initializer parsed"); + TUScope = 0; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index dd30c1261e..3c62c18558 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3026,11 +3026,11 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), II, R, TInfo, SC, SCAsWritten); - // If this decl has an auto type in need of deduction, mark the VarDecl so - // we can diagnose uses of it in its own initializer. - if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto) { - NewVD->setParsingAutoInit(R->getContainedAutoType()); - } + // If this decl has an auto type in need of deduction, make a note of the + // Decl so we can diagnose uses of it in its own initializer. + if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && + R->getContainedAutoType()) + ParsingInitForAutoVars.insert(NewVD); if (D.isInvalidType() || Invalid) NewVD->setInvalidDecl(); @@ -4534,8 +4534,6 @@ 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()) { - VDecl->setParsingAutoInit(false); - QualType DeducedType; if (!DeduceAutoType(VDecl->getType(), Init, DeducedType)) { Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure) @@ -4800,9 +4798,8 @@ void Sema::ActOnInitializerError(Decl *D) { if (!VD) return; // Auto types are meaningless if we can't make sense of the initializer. - if (VD->isParsingAutoInit()) { - VD->setParsingAutoInit(false); - VD->setInvalidDecl(); + if (ParsingInitForAutoVars.count(D)) { + D->setInvalidDecl(); return; } @@ -4840,8 +4837,6 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, // C++0x [dcl.spec.auto]p3 if (TypeMayContainAuto && Type->getContainedAutoType()) { - Var->setParsingAutoInit(false); - Diag(Var->getLocation(), diag::err_auto_var_requires_init) << Var->getDeclName() << Type; Var->setInvalidDecl(); @@ -5044,6 +5039,14 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { FinalizeVarWithDestructor(var, recordType); } +/// FinalizeDeclaration - called by ParseDeclarationAfterDeclarator to perform +/// any semantic actions necessary after any initializer has been attached. +void +Sema::FinalizeDeclaration(Decl *ThisDecl) { + // Note that we are no longer parsing the initializer for this declaration. + ParsingInitForAutoVars.erase(ThisDecl); +} + Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, Decl **Group, unsigned NumDecls) { diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index e8abab8476..c12534645f 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1078,6 +1078,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, if (Deleted) // FIXME: Source location is not very good. SetDeclDeleted(Member, D.getSourceRange().getBegin()); + FinalizeDeclaration(Member); + if (isInstField) FieldCollector->Add(cast(Member)); return Member; @@ -5972,8 +5974,6 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, // C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) { - VDecl->setParsingAutoInit(false); - // FIXME: n3225 doesn't actually seem to indicate this is ill-formed if (Exprs.size() > 1) { Diag(Exprs.get()[1]->getSourceRange().getBegin(), diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index e7d167ed38..4ac3538764 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -76,12 +76,10 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, } // See if this is an auto-typed variable whose initializer we are parsing. - if (const VarDecl *VD = dyn_cast(D)) { - if (VD->isParsingAutoInit()) { - Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer) - << D->getDeclName(); - return true; - } + if (ParsingInitForAutoVars.count(D)) { + Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer) + << D->getDeclName(); + return true; } // See if the decl is deprecated. diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index bd0a618283..139fafb346 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -3004,12 +3004,12 @@ Sema::DeduceAutoType(QualType Type, Expr *Init, QualType &Result) { LocalInstantiationScope InstScope(*this); // Build template void Func(FuncParam); - NamedDecl *TemplParam - = TemplateTypeParmDecl::Create(Context, 0, Loc, 0, 0, 0, false, false); - TemplateParameterList *TemplateParams - = TemplateParameterList::Create(Context, Loc, Loc, &TemplParam, 1, Loc); - QualType TemplArg = Context.getTemplateTypeParmType(0, 0, false); + TemplateTypeParmDecl TemplParam(0, Loc, 0, false, TemplArg, false); + NamedDecl *TemplParamPtr = &TemplParam; + FixedSizeTemplateParameterList<1> TemplateParams(Loc, Loc, &TemplParamPtr, + Loc); + QualType FuncParam = SubstituteAutoTransform(*this, TemplArg).TransformType(Type); @@ -3018,13 +3018,13 @@ Sema::DeduceAutoType(QualType Type, Expr *Init, QualType &Result) { Deduced.resize(1); QualType InitType = Init->getType(); unsigned TDF = 0; - if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams, + if (AdjustFunctionParmAndArgTypesForDeduction(*this, &TemplateParams, FuncParam, InitType, Init, TDF)) return false; TemplateDeductionInfo Info(Context, Loc); - if (::DeduceTemplateArguments(*this, TemplateParams, + if (::DeduceTemplateArguments(*this, &TemplateParams, FuncParam, InitType, Info, Deduced, TDF)) return false; diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp index 24780c6832..81f1a9f96e 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp @@ -3,12 +3,19 @@ void f() { auto a = a; // expected-error{{variable 'a' declared with 'auto' type cannot appear in its own initializer}} auto *b = b; // expected-error{{variable 'b' declared with 'auto' type cannot appear in its own initializer}} const auto c = c; // expected-error{{variable 'c' declared with 'auto' type cannot appear in its own initializer}} + if (auto d = d) {} // expected-error {{variable 'd' declared with 'auto' type cannot appear in its own initializer}} + auto e = ({ auto f = e; 0; }); // expected-error {{variable 'e' declared with 'auto' type cannot appear in its own initializer}} } void g() { auto a; // expected-error{{declaration of variable 'a' with type 'auto' requires an initializer}} auto *b; // expected-error{{declaration of variable 'b' with type 'auto *' requires an initializer}} + + if (auto b) {} // expected-error {{expected '='}} + for (;auto b;) {} // expected-error {{expected '='}} + while (auto b) {} // expected-error {{expected '='}} + if (auto b = true) { (void)b; } } auto n(1,2,3); // expected-error{{initializer for variable 'n' with type 'auto' contains multiple expressions}} @@ -21,7 +28,7 @@ namespace N void h() { auto b = 42ULL; - for (auto c = 0; c < 100; ++c) { + for (auto c = 0; c < b; ++c) { } } -- 2.40.0