Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -1192,7 +1192,8 @@ /// \brief C++11 deduced auto type. QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto, - bool IsDependent) const; + bool IsDependent, bool IsParameterPack, + unsigned Index) const; /// \brief C++11 deduction pattern for 'auto' type. QualType getAutoDeductType() const; Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -41,6 +41,8 @@ class Type; class ExtQuals; class QualType; + class TypeLoc; + class AutoTypeLoc; } namespace llvm { @@ -1356,6 +1358,9 @@ /// Was this placeholder type spelled as 'decltype(auto)'? unsigned IsDecltypeAuto : 1; + + unsigned Index : 16; + }; union { @@ -1719,10 +1724,16 @@ /// not refer to a CXXRecordDecl, returns NULL. const CXXRecordDecl *getPointeeCXXRecordDecl() const; - /// \brief Get the AutoType whose type will be deduced for a variable with - /// an initializer of this type. This looks through declarators like pointer - /// types, but not through decltype or typedefs. - AutoType *getContainedAutoType() const; + bool containsAutoType() const; + + /// \brief Get all the AutoTypes whose types will be deduced for a variable + /// with an initializer of this type. This looks through declarators like + /// pointer types, but not through decltype or typedefs. + SmallVector getContainedAutoTypes() const; + + /// \brief Get all the AutoTypeLocs within a typelocation + static SmallVector + getContainedAutoTypeLocs(TypeLoc TL); /// Member-template getAs'. Look through sugar for /// an instance of \. This scheme will eventually @@ -3703,52 +3714,109 @@ } }; -/// \brief Represents a C++11 auto or C++1y decltype(auto) type. +/// \brief Represents a C++11 auto or C++14 decltype(auto) type or in C++1z +/// signifies abbreviated template syntax or multi-auto deduction. /// -/// These types are usually a placeholder for a deduced type. However, before -/// the initializer is attached, or if the initializer is type-dependent, there -/// is no deduced type and an auto type is canonical. In the latter case, it is -/// also a dependent type. +/// There are 4 essentially different notions that are modeled by this type: +/// 1) decltype(auto) +/// 2) 'auto' signifying a trailing-return-type : +/// - auto f() -> int; <-- no return type deduction. +/// - auto (*fp)()->int = &f; <-- no type inference. +/// 3) 'auto' contained within a return type of a function or variable type +/// requiring deduction (return type or initializer) +/// - auto f(int); <-- return type deduction, +/// not abbreviated template syntax. +/// - auto (*fp)(auto) = f; <-- variable type inference, +/// not abbreviated tempalte syntax. +/// 4) 'auto' contained within a parameter-type of a function declaration. +/// - void f(auto); <-- template void f(T); +/// - auto f(auto fp()); <-- template auto f(T fp()); +/// - auto f(auto fp()->int); <-- not an abbreviated template +/// +/// As a more involved example, consider the following transformation: +/// pair f(auto fp(auto, auto) -> auto*) :=> +/// template +/// pair f(auto fp(T0, T1) -> T2*); + +/// In order to differentiate an 'auto' that signifies an abbreviated template +/// parameter vs type-inference from an initializer, an AutoType can start its +/// life as either dependent or non-dependent. An auto that represents +/// abbreviated template syntax must start its life as dependent, whereas one +/// for type-inference from a return type or variable initializer must start its +/// life as non-dependent. An AutoType that denotes abbreviated template syntax +/// (i.e. dependent), is replaced with a corresponding template type parameter +/// during initial construction of the FunctionDecl AST node, and thus does not +/// survive in the AST. On the other hand an AutoType that denotes return-type +/// deduction or type-inference initiates life as non-dependent, but can be +/// deduced to a dependent type if the initializer is dependent (these +/// constructs do survive in the AST - and get instantiated/transformed with +/// non-dependent types when required). See the SubstituteAutosTransformer +/// for additional insight into this. + +/// These types are usually a placeholder for a deduced type. +/// However, before the initializer is attached, or if the initializer is +/// type-dependent, there is no deduced type and an auto type is canonical - but +/// any AutoType with a non-zero index is canonicalized by the corresponding +/// zero indexed auto type - this allows all AutoTypes with the same 'bits' +/// asides from the Index, to compare the same (agnostic of their index which is +/// mainly used during substitution). canonical type. In the case that Auto has +/// a dependent initializer, it gets 'deduced' (or marked) as a dependent type. class AutoType : public Type, public llvm::FoldingSetNode { - AutoType(QualType DeducedType, bool IsDecltypeAuto, - bool IsDependent) - : Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType, - /*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent, - /*VariablyModified=*/false, - /*ContainsParameterPack=*/DeducedType.isNull() - ? false : DeducedType->containsUnexpandedParameterPack()) { + AutoType(QualType DeducedType, bool IsDecltypeAuto, bool IsDependent, + bool IsParameterPack, unsigned Index, + const AutoType *UndeducedCanonType) + : Type(Auto, + /*Canonical Type*/ + DeducedType.isNull() + ? QualType(UndeducedCanonType ? UndeducedCanonType : this, 0) + : DeducedType, + /*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent, + /*VariablyModified=*/false, + /*ContainsParameterPack=*/DeducedType.isNull() + ? IsParameterPack + : DeducedType->containsUnexpandedParameterPack()) { assert((DeducedType.isNull() || !IsDependent) && "auto deduced to dependent type"); + assert((!Index || !DeducedType.isNull() || + (UndeducedCanonType && UndeducedCanonType->getIndex() == 0)) && + "An AutoType with a non-zero index must have a zero indexed " + "canonical type"); AutoTypeBits.IsDecltypeAuto = IsDecltypeAuto; + AutoTypeBits.Index = Index; } friend class ASTContext; // ASTContext creates these public: bool isDecltypeAuto() const { return AutoTypeBits.IsDecltypeAuto; } - + unsigned getIndex() const { return AutoTypeBits.Index; } bool isSugared() const { return !isCanonicalUnqualified(); } QualType desugar() const { return getCanonicalTypeInternal(); } /// \brief Get the type deduced for this auto type, or null if it's either /// not been deduced or was deduced to a dependent type. QualType getDeducedType() const { - return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType(); + return isa(getCanonicalTypeInternal()) + ? QualType() + : getCanonicalTypeInternal(); } bool isDeduced() const { - return !isCanonicalUnqualified() || isDependentType(); + return !getDeducedType().isNull() || isDependentType(); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getDeducedType(), isDecltypeAuto(), - isDependentType()); + isDependentType(), containsUnexpandedParameterPack(), getIndex()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced, - bool IsDecltypeAuto, bool IsDependent) { + bool IsDecltypeAuto, bool IsDependent, + bool IsParameterPack, unsigned Index) { ID.AddPointer(Deduced.getAsOpaquePtr()); + ID.AddBoolean(IsParameterPack); ID.AddBoolean(IsDecltypeAuto); ID.AddBoolean(IsDependent); + ID.AddInteger(Index); } static bool classof(const Type *T) { @@ -5192,8 +5260,16 @@ } inline bool Type::isUndeducedType() const { - const AutoType *AT = getContainedAutoType(); - return AT && !AT->isDeduced(); + auto ATs = getContainedAutoTypes(); + const bool IsUndeduced = ATs.size() && !ATs.front()->isDeduced(); + assert([&] { + for (auto&& AT : ATs) { + if (AT->isDeduced() == IsUndeduced) + return false; + } + return true; + }() && "All autos should either be deduced or undeduced within a type"); + return IsUndeduced; } /// \brief Determines whether this is a type for which one can define Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -1694,7 +1694,7 @@ def err_auto_fn_deduction_failure : Error< "cannot deduce return type %0 from returned value of type %1">; def err_auto_fn_different_deductions : Error< - "'%select{auto|decltype(auto)}0' in return type deduced as %1 here but " + "'%select{auto|decltype(auto)}0' containing return type deduced as %1 here but " "deduced as %2 in earlier return statement">; def err_auto_fn_used_before_defined : Error< "function %0 with deduced return type cannot be used before it is defined">; Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -1180,6 +1180,10 @@ void ParseLexedMethodDef(LexedMethod &LM); void ParseLexedMemberInitializers(ParsingClass &Class); void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI); + void ParseLexedDefaultArguments( + MutableArrayRef DefaultArgs); + void ParseAbbreviatedFunctionTemplateDefaultArgs( + Declarator &FunDeclarator); void ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod); bool ConsumeAndStoreFunctionPrologue(CachedTokens &Toks); bool ConsumeAndStoreInitializer(CachedTokens &Toks, CachedInitKind CIK); Index: include/clang/Sema/DeclSpec.h =================================================================== --- include/clang/Sema/DeclSpec.h +++ include/clang/Sema/DeclSpec.h @@ -399,10 +399,6 @@ ObjCDeclSpec *ObjCQualifiers; - static bool isTypeRep(TST T) { - return (T == TST_typename || T == TST_typeofType || - T == TST_underlyingType || T == TST_atomic); - } static bool isExprRep(TST T) { return (T == TST_typeofExpr || T == TST_decltype); } @@ -410,6 +406,10 @@ DeclSpec(const DeclSpec &) = delete; void operator=(const DeclSpec &) = delete; public: + static bool isTypeRep(TST T) { + return (T == TST_typename || T == TST_typeofType || + T == TST_underlyingType || T == TST_atomic); + } static bool isDeclRep(TST T) { return (T == TST_enum || T == TST_struct || T == TST_interface || T == TST_union || Index: include/clang/Sema/Scope.h =================================================================== --- include/clang/Sema/Scope.h +++ include/clang/Sema/Scope.h @@ -358,7 +358,32 @@ bool isFunctionPrototypeScope() const { return getFlags() & Scope::FunctionPrototypeScope; } + bool isFunctionDeclarationScope() const { + return getFlags() & Scope::FunctionDeclarationScope; + } + + /// Returns true if this scope is a function prototype scope nested within a + /// function declaration scope. This is helpful when we need to determine + /// whether an 'auto' should be marked as an auto for deduction vs abbreviated + /// template syntax. If this is true, then the 'auto' signifies a template + /// type parameter. + bool isFunctionPrototypeScopeNestedWithinFunctionDeclarationScope() const { + const Scope *S = this; + + while (S && S->isFunctionPrototypeScope()) { + if (S->isFunctionDeclarationScope()) + return true; + if (S = S->getParent()) { + // If we have crawled up into the TU, a classcope or a + // templateparamscope, we can not be within a function declaration if we + // haven't found one already. + if (!S->getParent() || S->isClassScope() || S->isTemplateParamScope()) + return false; + } + } + return false; + } /// isAtCatchScope - Return true if this scope is \@catch. bool isAtCatchScope() const { return getFlags() & Scope::AtCatchScope; Index: include/clang/Sema/ScopeInfo.h =================================================================== --- include/clang/Sema/ScopeInfo.h +++ include/clang/Sema/ScopeInfo.h @@ -654,23 +654,7 @@ /// \brief Offsets into the ArrayIndexVars array at which each capture starts /// its list of array index variables. SmallVector ArrayIndexStarts; - - /// \brief If this is a generic lambda, use this as the depth of - /// each 'auto' parameter, during initial AST construction. - unsigned AutoTemplateParameterDepth; - - /// \brief Store the list of the auto parameters for a generic lambda. - /// If this is a generic lambda, store the list of the auto - /// parameters converted into TemplateTypeParmDecls into a vector - /// that can be used to construct the generic lambda's template - /// parameter list, during initial AST construction. - SmallVector AutoTemplateParams; - - /// If this is a generic lambda, and the template parameter - /// list has been created (from the AutoTemplateParams) then - /// store a reference to it (cache it to avoid reconstructing it). - TemplateParameterList *GLTemplateParameterList; - + /// \brief Contains all variable-referring-expressions (i.e. DeclRefExprs /// or MemberExprs) that refer to local variables in a generic lambda /// or a lambda in a potentially-evaluated-if-used context. @@ -698,8 +682,7 @@ LambdaScopeInfo(DiagnosticsEngine &Diag) : CapturingScopeInfo(Diag, ImpCap_None), Lambda(nullptr), CallOperator(nullptr), NumExplicitCaptures(0), Mutable(false), - ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false), - AutoTemplateParameterDepth(0), GLTemplateParameterList(nullptr) + ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false) { Kind = SK_Lambda; } Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -148,6 +148,7 @@ class OverloadExpr; class ParenListExpr; class ParmVarDecl; + class ParsingFunctionDeclarationAbbreviatedTemplateInfo; class Preprocessor; class PseudoDestructorTypeStorage; class PseudoObjectExpr; @@ -168,6 +169,7 @@ class TypedefDecl; class TypedefNameDecl; class TypeLoc; + class TypeLocBuilder; class TypoCorrectionConsumer; class UnqualifiedId; class UnresolvedLookupExpr; @@ -204,9 +206,10 @@ void threadSafetyCleanup(BeforeSet* Cache); } -// FIXME: No way to easily map from TemplateTypeParmTypes to +// FIXME: No way to easily map from TemplateTypeParmTypes or AutoTypes to // TemplateTypeParmDecls, so we have this horrible PointerUnion. -typedef std::pair, +typedef std::pair, SourceLocation> UnexpandedParameterPack; /// Sema - This implements semantic analysis and AST building for C. @@ -1070,11 +1073,6 @@ void PushBlockScope(Scope *BlockScope, BlockDecl *Block); sema::LambdaScopeInfo *PushLambdaScope(); - /// \brief This is used to inform Sema what the current TemplateParameterDepth - /// is during Parsing. Currently it is used to pass on the depth - /// when parsing generic lambda 'auto' parameters. - void RecordParsingTemplateParameterDepth(unsigned Depth); - void PushCapturedRegionScope(Scope *RegionScope, CapturedDecl *CD, RecordDecl *RD, CapturedRegionKind K); @@ -1086,7 +1084,7 @@ sema::FunctionScopeInfo *getCurFunction() const { return FunctionScopes.back(); } - + sema::FunctionScopeInfo *getEnclosingFunction() const { if (FunctionScopes.empty()) return nullptr; @@ -4803,14 +4801,16 @@ CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange, TypeSourceInfo *Info, bool KnownDependent, - LambdaCaptureDefault CaptureDefault); + LambdaCaptureDefault CaptureDefault, + bool IsGenericLambda); /// \brief Start the definition of a lambda expression. CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodType, SourceLocation EndLoc, - ArrayRef Params); + ArrayRef Params, + TemplateParameterList *GeneriLambdaTPL); /// \brief Endow the lambda scope info with the relevant properties. void buildLambdaScope(sema::LambdaScopeInfo *LSI, @@ -6227,6 +6227,63 @@ TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType Replacement); + ParsingFunctionDeclarationAbbreviatedTemplateInfo * + getAbbreviatedFunctionTemplateInfo() { + return CurAbbreviatedFunctionTemplateInfo; + } + + TemplateTypeParmDecl *makeTemplateTypeParameter( + ASTContext &Context, const unsigned Depth, const unsigned Position, + const SourceLocation StartLoc, const bool IsParameterPack = false, + const std::string InventedTemplateParamPrefix = "$auto-"); + + // Given an abbreviated function template type (that contains dependent + // AutoTypes within its parameters), any parsed template parameter lists for + // the current declarator, and a fully parsed function declarator, return a + // re-constructed normalized function type whose parameters contain + // corresponding references to template parameter types/decls. This function + // takes any existing TPLs into account, determines if the explicit TPL (if + // any) belongs to the function declarator or to its parent scope, and either + // adds the 'auto' template parameters to the current TPL, or creates one, + // with each corresponding template parameter assigned the appropriate depth + // (from the parser) and the index (in order of appearance where it designates + // a placeholder). + // For e.g. + // auto f(auto (*)(auto)) ==> + // template auto f(T0 (*)(T1)); + // auto f(auto (*)(auto)->auto) ==> + // template auto f(T1 (*)(T0)); + + TypeSourceInfo * + normalizeAbbreviatedTemplateType(TypeSourceInfo *AutoContainingTSI, + MultiTemplateParamsArg CurTemplateParamLists, + Declarator &FunDeclarator); + + TypeSourceInfo *replaceEachDependentAutoWithCorrespondingTemplateTypes( + TypeSourceInfo *AutoContainingTSI, + ArrayRef CorrespondingTemplateTypes); + + TypeSourceInfo * + makeAllContainedAutosVariadic(TypeSourceInfo *AutoContainingTSI); + TypeSourceInfo * + makeAllContainedAutosDependent(TypeSourceInfo *AutoContainingTSI); + QualType makeAllContainedAutosDependent(QualType AutoContainingType); + + QualType getAppropriatelyDependentAutoType(bool HasEllipsis, Declarator *D); + + std::vector + Sema::getCorrespondingTemplateTypeParmDeclsForAutoTypes( + const unsigned TemplateParamDepthForAllAutos, + const unsigned TemplateParamIndexForFirstAuto, + ArrayRef ContainedAutoTypeLocs); + + static std::vector Sema::getTypesFromTemplateTypeParamDecls( + ArrayRef TemplateTypeParmDecls); + + TemplateParameterList *getMatchingTemplateParameterListForDeclarator( + MultiTemplateParamsArg CurTemplateParamLists, + const Declarator &FunDeclarator); + /// \brief Result type of DeduceAutoType. enum DeduceAutoResult { DAR_Succeeded, @@ -6246,7 +6303,7 @@ bool DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, SourceLocation ReturnLoc, - Expr *&RetExpr, AutoType *AT); + Expr *&RetExpr); FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, @@ -6924,6 +6981,14 @@ void InstantiateExceptionSpec(SourceLocation PointOfInstantiation, FunctionDecl *Function); + + /// Introduce the instantiated function parameters into the local + /// instantiation scope, and set the parameter names to those used in the + /// template. + bool addInstantiatedParametersToScope( + FunctionDecl *Function, const FunctionDecl *PatternDecl, + LocalInstantiationScope &Scope, + const MultiLevelTemplateArgumentList &TemplateArgs); void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive = false, @@ -8700,8 +8765,26 @@ /// The parser maintains this state here. Scope *CurScope; + /// \brief The parser's current TemplateParameterDepth to assign to the next + /// template parameter scope + /// + /// The parser maintains this state - Sema only reads it during initial AST + /// construction (do not rely on this during any subsequent + /// transformations/instantiations) + const unsigned *ParsingTemplateParameterDepthPtr; mutable IdentifierInfo *Ident_super; mutable IdentifierInfo *Ident___float128; +public: + // Track information regarding abbreviated templates (i.e. 'auto' templates) + // when parsing (function declarators and lambda expressions) and initially + // constructing the AST. + ParsingFunctionDeclarationAbbreviatedTemplateInfo * + CurAbbreviatedFunctionTemplateInfo; + + const unsigned &getParsingTemplateParameterDepth() const { + assert(ParsingTemplateParameterDepthPtr); + return *ParsingTemplateParameterDepthPtr; + } protected: friend class Parser; Index: include/clang/Sema/Template.h =================================================================== --- include/clang/Sema/Template.h +++ include/clang/Sema/Template.h @@ -20,6 +20,34 @@ #include namespace clang { + + class ParsingFunctionDeclarationAbbreviatedTemplateInfo { + ParsingFunctionDeclarationAbbreviatedTemplateInfo *Prev; + public: + Sema &S; + + /// If this is an abbreviated template, and the template parameter list has + /// been created then store a reference to it. + TemplateParameterList *AbbreviatedTemplateParameterList; + + /// Did the user provide an explicit tpl in addition to using abbreviated + /// template syntax? If so, track it. + TemplateParameterList *ExplicitlyProvidedTemplateParameterList; + unsigned CurAutoIndex; + ParsingFunctionDeclarationAbbreviatedTemplateInfo( + Sema &S) + : S(S), + Prev(S.CurAbbreviatedFunctionTemplateInfo), + AbbreviatedTemplateParameterList(nullptr), + ExplicitlyProvidedTemplateParameterList(nullptr), CurAutoIndex(0) { + S.CurAbbreviatedFunctionTemplateInfo = this; + } + + ~ParsingFunctionDeclarationAbbreviatedTemplateInfo() { + S.CurAbbreviatedFunctionTemplateInfo = Prev; + } + }; + /// \brief Data structure that captures multiple levels of template argument /// lists for use in template instantiation. /// Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -28,7 +28,6 @@ #include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" -#include "clang/AST/TypeLoc.h" #include "clang/AST/VTableBuilder.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" @@ -3815,20 +3814,32 @@ /// deduced to the given type, or to the canonical undeduced 'auto' type, or the /// canonical deduced-but-dependent 'auto' type. QualType ASTContext::getAutoType(QualType DeducedType, bool IsDecltypeAuto, - bool IsDependent) const { - if (DeducedType.isNull() && !IsDecltypeAuto && !IsDependent) + bool IsDependent, + bool IsParameterPack, unsigned Index) const { + if (DeducedType.isNull() && !IsDecltypeAuto && !IsDependent && + !IsParameterPack && !Index) return getAutoDeductType(); // Look in the folding set for an existing type. void *InsertPos = nullptr; llvm::FoldingSetNodeID ID; - AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent); + AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent, + /*IsParameterPack*/ IsParameterPack, Index); if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); - + // An AutoType with a nonZero Index has its Zero Index counterpart as its + // canonical type, if it doesn't have a deduced type. + const AutoType *CanonicalAutoType = nullptr; + if (Index != 0 && DeducedType.isNull()) { + CanonicalAutoType = + cast(getAutoType(DeducedType, IsDecltypeAuto, IsDependent, + IsParameterPack, /*Index*/0).getTypePtr()); + } AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType, IsDecltypeAuto, - IsDependent); + IsDependent, + IsParameterPack, + Index, CanonicalAutoType); Types.push_back(AT); if (InsertPos) AutoTypes.InsertNode(AT, InsertPos); @@ -3868,7 +3879,8 @@ if (AutoDeductTy.isNull()) AutoDeductTy = QualType( new (*this, TypeAlignment) AutoType(QualType(), /*decltype(auto)*/false, - /*dependent*/false), + /*dependent*/false, + /*IsParameterPack*/false, /*Index*/0, nullptr), 0); return AutoDeductTy; } @@ -3881,6 +3893,7 @@ return AutoRRefDeductTy; } + /// getTagDeclType - Return the unique reference to the type for the /// specified TagDecl (struct/union/class/enum) decl. QualType ASTContext::getTagDeclType(const TagDecl *Decl) const { Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -1701,9 +1701,9 @@ if (ToDeduced.isNull()) return QualType(); } - - return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto(), - /*IsDependent*/false); + return Importer.getToContext().getAutoType( + ToDeduced, T->isDecltypeAuto(), T->isDependentType(), + T->containsUnexpandedParameterPack(), T->getIndex()); } QualType ASTNodeImporter::VisitRecordType(const RecordType *T) { Index: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ lib/AST/MicrosoftMangle.cpp @@ -1592,8 +1592,12 @@ Out << '@'; } else { QualType ResultType = Proto->getReturnType(); - if (const auto *AT = - dyn_cast_or_null(ResultType->getContainedAutoType())) { + // FVFIXME: We need to teach the mangler how to mangle multi-auto containing + // return types (pair). + const auto ContainedAutos = ResultType->getContainedAutoTypes(); + const AutoType *AT = + ContainedAutos.size() ? ContainedAutos.front() : nullptr; + if (AT) { Out << '?'; mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false); Out << '?'; Index: lib/AST/NestedNameSpecifier.cpp =================================================================== --- lib/AST/NestedNameSpecifier.cpp +++ lib/AST/NestedNameSpecifier.cpp @@ -201,7 +201,9 @@ case TypeSpec: case TypeSpecWithTemplate: - return getAsType()->isDependentType(); + // Undeduced 'auto' within NNS should behave as if dependent, until the + // initializer is used to deduce it. + return getAsType()->isDependentType() || getAsType()->isUndeducedType(); } llvm_unreachable("Invalid NNS Kind!"); Index: lib/AST/TemplateBase.cpp =================================================================== --- lib/AST/TemplateBase.cpp +++ lib/AST/TemplateBase.cpp @@ -104,10 +104,29 @@ case Null: llvm_unreachable("Should not have a NULL template argument"); - case Type: + case Type: { + + auto IsPackExpansionOfNonDependentTemplateAlias = [this] { + // This is to prevent: + // template struct S {}; + // template using X = int; + // template void h(S...>) {} + // http://llvm.org/bugs/show_bug.cgi?id=21289 + // http://www2.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1980 + // Not sure if this is the intended direction... + QualType QTy = getAsType(); + if (const PackExpansionType *PTy = dyn_cast(QTy)) + if (const TemplateSpecializationType *TTy = + dyn_cast(PTy->getPattern())) + if (TTy->isTypeAlias()) { + assert(!TTy->getAliasedType()->isDependentType()); + return true; + } + return false; + }; return getAsType()->isDependentType() || - isa(getAsType()); - + IsPackExpansionOfNonDependentTemplateAlias(); + } case Template: return getAsTemplate().isDependent(); Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -20,6 +20,8 @@ #include "clang/AST/Expr.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeLocVisitor.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/Specifiers.h" #include "llvm/ADT/APSInt.h" @@ -553,62 +555,184 @@ return nullptr; } + + namespace { + // Make Sure Whatever changes are made to this, are also made to the analogous + // NonTypeLoc Visitor below that is location agnostic (GetContainedAutoVisitor). + class GetContainedAutoLocVisitor + : public TypeLocVisitor { + public: + using ContainerTy = SmallVector; + ContainerTy ContainedAutoTypes; + + GetContainedAutoLocVisitor() {} + + // The 'auto' type itself. + void VisitAutoTypeLoc(AutoTypeLoc AT) { ContainedAutoTypes.push_back(AT); } + + // Only these types can contain the desired 'auto' type. + void VisitPointerTypeLoc(PointerTypeLoc TL) { + return Visit(TL.getPointeeLoc()); + } + void VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + return Visit(TL.getPointeeLoc()); + } + void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + return Visit(TL.getUnqualifiedLoc()); + } + void VisitReferenceTypeLoc(ReferenceTypeLoc TL) { + return Visit(TL.getPointeeLoc()); + } + void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + Visit(TL.getPointeeLoc()); + if (TL.getClassTInfo()) + return Visit(TL.getClassTInfo()->getTypeLoc()); + } + void VisitArrayTypeLoc(ArrayTypeLoc TL) { return Visit(TL.getElementLoc()); } + + void VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { + const bool HasTrailingReturn = TL.getTypePtr()->hasTrailingReturn(); + + if (!HasTrailingReturn) + Visit(TL.getReturnLoc()); + + for (ParmVarDecl *PD : TL.getParams()) { + if (PD) // We need this check for conversion from lambda to block-ptr + Visit(PD->getTypeSourceInfo()->getTypeLoc()); + } + if (HasTrailingReturn) + Visit(TL.getReturnLoc()); + } + + void VisitParenTypeLoc(ParenTypeLoc TL) { return Visit(TL.getInnerLoc()); } + void VisitAttributedTypeLoc(AttributedTypeLoc TL) { + return Visit(TL.getModifiedLoc()); + } + void VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { + return Visit(TL.getOriginalLoc()); + } + void VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + NestedNameSpecifierLoc NNSLoc = TL.getQualifierLoc(); + if (const NestedNameSpecifier *NNS = NNSLoc.getNestedNameSpecifier()) { + if (const Type *Ty = NNS->getAsType()) + Visit(NNSLoc.getTypeLoc()); + } + return Visit(TL.getNamedTypeLoc()); + } + void VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) { + return Visit(TL.getPatternLoc()); + } + void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { + for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I) { + TemplateArgumentLoc TAL = TL.getArgLoc(I); + if (TAL.getArgument().getKind() == TemplateArgument::Type) + Visit(TAL.getTypeSourceInfo()->getTypeLoc()); + } + } + }; + // Please ensure this visitor is synced with the GetContainedAutoLocVisitor Above. class GetContainedAutoVisitor : - public TypeVisitor { + public TypeVisitor { + const bool FindOnlyFirstAuto; public: - using TypeVisitor::Visit; - AutoType *Visit(QualType T) { + GetContainedAutoVisitor(bool FindOnlyFirstAuto = false) + : FindOnlyFirstAuto(FindOnlyFirstAuto) {} + + using inherited = TypeVisitor < GetContainedAutoVisitor >; + using ContainerTy = SmallVector; + ContainerTy ContainedAutoTypes; + void Visit(QualType T) { if (T.isNull()) - return nullptr; - return Visit(T.getTypePtr()); + return; + if (FindOnlyFirstAuto && ContainedAutoTypes.size()) return; + inherited::Visit(T.getTypePtr()); } // The 'auto' type itself. - AutoType *VisitAutoType(const AutoType *AT) { - return const_cast(AT); + void VisitAutoType(const AutoType *AT) { + ContainedAutoTypes.push_back(AT); } // Only these types can contain the desired 'auto' type. - AutoType *VisitPointerType(const PointerType *T) { + void VisitPointerType(const PointerType *T) { return Visit(T->getPointeeType()); } - AutoType *VisitBlockPointerType(const BlockPointerType *T) { + void VisitBlockPointerType(const BlockPointerType *T) { return Visit(T->getPointeeType()); } - AutoType *VisitReferenceType(const ReferenceType *T) { + void VisitReferenceType(const ReferenceType *T) { return Visit(T->getPointeeTypeAsWritten()); } - AutoType *VisitMemberPointerType(const MemberPointerType *T) { - return Visit(T->getPointeeType()); + void VisitMemberPointerType(const MemberPointerType *T) { + Visit(T->getPointeeType()); + Visit(QualType(T->getClass(),0)); + return; } - AutoType *VisitArrayType(const ArrayType *T) { + void VisitArrayType(const ArrayType *T) { return Visit(T->getElementType()); } - AutoType *VisitDependentSizedExtVectorType( + void VisitDependentSizedExtVectorType( const DependentSizedExtVectorType *T) { return Visit(T->getElementType()); } - AutoType *VisitVectorType(const VectorType *T) { + void VisitVectorType(const VectorType *T) { return Visit(T->getElementType()); } - AutoType *VisitFunctionType(const FunctionType *T) { + void VisitFunctionType(const FunctionType *T) { return Visit(T->getReturnType()); } - AutoType *VisitParenType(const ParenType *T) { + void VisitParenType(const ParenType *T) { return Visit(T->getInnerType()); } - AutoType *VisitAttributedType(const AttributedType *T) { + void VisitAttributedType(const AttributedType *T) { return Visit(T->getModifiedType()); } - AutoType *VisitAdjustedType(const AdjustedType *T) { + void VisitAdjustedType(const AdjustedType *T) { return Visit(T->getOriginalType()); } + void VisitElaboratedType(const ElaboratedType *T) { + if (const NestedNameSpecifier *NNS = T->getQualifier()) { + if (const Type *Ty = NNS->getAsType()) + Visit(QualType(Ty, 0)); + } + return Visit(T->getNamedType()); + } + void VisitPackExpansionType(const PackExpansionType *T) { + return Visit(T->getPattern()); + } + void VisitFunctionProtoType(const FunctionProtoType *T) { + Visit(T->getReturnType()); + for (QualType Ty : T->getParamTypes()) + Visit(Ty); + } + void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { + for (unsigned I = 0, N = T->getNumArgs(); I != N; ++I) { + const TemplateArgument &TA = T->getArg(I); + if (TA.getKind() == TA.Type) + Visit(TA.getAsType()); + } + } + }; } +// This always returns the first auto-type encountered +bool Type::containsAutoType() const { + GetContainedAutoVisitor AV(/*FindOnlyFirstAuto*/true); + AV.Visit(QualType(this, 0)); + return AV.ContainedAutoTypes.size(); +} + +SmallVector Type::getContainedAutoTypes() const { + GetContainedAutoVisitor AV; + AV.Visit(QualType(this, 0)); + return AV.ContainedAutoTypes; +} -AutoType *Type::getContainedAutoType() const { - return GetContainedAutoVisitor().Visit(this); +SmallVector Type::getContainedAutoTypeLocs(TypeLoc TL) { + GetContainedAutoLocVisitor AV; + AV.Visit(TL); + return AV.ContainedAutoTypes; } bool Type::hasIntegerRepresentation() const { @@ -1993,7 +2117,6 @@ InstantiationDependent = true; return true; } - if (Args[i].getArgument().isInstantiationDependent()) InstantiationDependent = true; } Index: lib/CodeGen/CGDebugInfo.cpp =================================================================== --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -1188,7 +1188,7 @@ if (!Method || Method->isImplicit()) continue; - if (Method->getType()->getAs()->getContainedAutoType()) + if (Method->getType()->getAs()->containsAutoType()) continue; // Reuse the existing member function declaration if it exists. Index: lib/Parse/ParseCXXInlineMethods.cpp =================================================================== --- lib/Parse/ParseCXXInlineMethods.cpp +++ lib/Parse/ParseCXXInlineMethods.cpp @@ -105,7 +105,7 @@ DefinitionKind == FDK_Definition && !D.getDeclSpec().isConstexprSpecified() && !(FnD && FnD->getAsFunction() && - FnD->getAsFunction()->getReturnType()->getContainedAutoType()) && + FnD->getAsFunction()->getReturnType()->containsAutoType()) && ((Actions.CurContext->isDependentContext() || (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && TemplateInfo.Kind != ParsedTemplateInfo::ExplicitSpecialization)) && @@ -290,27 +290,14 @@ Class.TagOrTemplate); } -void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { - // If this is a member template, introduce the template parameter scope. - ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); - TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); - if (LM.TemplateScope) { - Actions.ActOnReenterTemplateScope(getCurScope(), LM.Method); - ++CurTemplateDepthTracker; - } - // Start the delayed C++ method declaration - Actions.ActOnStartDelayedCXXMethodDeclaration(getCurScope(), LM.Method); - - // Introduce the parameters into scope and parse their default - // arguments. - ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope | - Scope::FunctionDeclarationScope | Scope::DeclScope); - for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) { - auto Param = cast(LM.DefaultArgs[I].Param); +void Parser::ParseLexedDefaultArguments( + MutableArrayRef DefaultArgs) { + for (unsigned I = 0, N = DefaultArgs.size(); I != N; ++I) { + auto Param = cast(DefaultArgs[I].Param); + const bool HasUnparsed = Param->hasUnparsedDefaultArg(); // Introduce the parameter into scope. - bool HasUnparsed = Param->hasUnparsedDefaultArg(); Actions.ActOnDelayedCXXMethodParameter(getCurScope(), Param); - if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) { + if (CachedTokens *Toks = DefaultArgs[I].Toks) { // Mark the end of the default argument so that we know when to stop when // we parse it later on. Token LastDefaultArgToken = Toks->back(); @@ -371,10 +358,11 @@ ConsumeAnyToken(); delete Toks; - LM.DefaultArgs[I].Toks = nullptr; + DefaultArgs[I].Toks = nullptr; } else if (HasUnparsed) { assert(Param->hasInheritedDefaultArg()); - FunctionDecl *Old = cast(LM.Method)->getPreviousDecl(); + FunctionDecl *Old = + cast(Param->getDeclContext())->getPreviousDecl(); ParmVarDecl *OldParam = Old->getParamDecl(I); assert (!OldParam->hasUnparsedDefaultArg()); if (OldParam->hasUninstantiatedDefaultArg()) @@ -384,6 +372,23 @@ Param->setDefaultArg(OldParam->getInit()); } } +} +void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { + // If this is a member template, introduce the template parameter scope. + ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (LM.TemplateScope) { + Actions.ActOnReenterTemplateScope(getCurScope(), LM.Method); + ++CurTemplateDepthTracker; + } + // Start the delayed C++ method declaration + Actions.ActOnStartDelayedCXXMethodDeclaration(getCurScope(), LM.Method); + + // Introduce the parameters into scope and parse their default + // arguments. + ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope | + Scope::FunctionDeclarationScope | Scope::DeclScope); + ParseLexedDefaultArguments(LM.DefaultArgs); // Parse a delayed exception-specification, if there is one. if (CachedTokens *Toks = LM.ExceptionSpecTokens) { @@ -492,8 +497,10 @@ if (LM.TemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), LM.D); ++CurTemplateDepthTracker; + } else if (isa(LM.D)) { + // This must be an abbreviated function template ... + ++CurTemplateDepthTracker; } - assert(!LM.Toks.empty() && "Empty body!"); Token LastBodyToken = LM.Toks.back(); Token BodyEnd; Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -24,6 +24,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/Template.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" @@ -1383,7 +1384,6 @@ // Must temporarily exit the objective-c container scope for // parsing c none objective-c decls. ObjCDeclContextSwitch ObjCDC(*this); - Decl *SingleDecl = nullptr; Decl *OwnedType = nullptr; switch (Tok.getKind()) { @@ -1446,6 +1446,7 @@ SourceLocation &DeclEnd, ParsedAttributesWithRange &Attrs, bool RequireSemi, ForRangeInit *FRI) { + ParsingFunctionDeclarationAbbreviatedTemplateInfo AFTI(Actions); // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); @@ -1628,6 +1629,7 @@ unsigned Context, SourceLocation *DeclEnd, ForRangeInit *FRI) { + // Parse the first declarator. ParsingDeclarator D(*this, DS, static_cast(Context)); ParseDeclarator(D); @@ -1775,11 +1777,10 @@ // short var __attribute__((common)); -> declarator // short x, __attribute__((common)) var; -> declarator MaybeParseGNUAttributes(D); - + ParsingFunctionDeclarationAbbreviatedTemplateInfo AFTI(Actions); // MSVC parses but ignores qualifiers after the comma as an extension. if (getLangOpts().MicrosoftExt) DiagnoseAndSkipExtendedMicrosoftTypeAttributes(); - ParseDeclarator(D); if (!D.isInvalidType()) { Decl *ThisDecl = ParseDeclarationAfterDeclarator(D); @@ -1918,6 +1919,10 @@ break; } } + if (Actions.getAbbreviatedFunctionTemplateInfo() && + Actions.getAbbreviatedFunctionTemplateInfo() + ->AbbreviatedTemplateParameterList) + ParseAbbreviatedFunctionTemplateDefaultArgs(D); bool TypeContainsAuto = D.getDeclSpec().containsPlaceholderType(); @@ -3025,9 +3030,16 @@ if (!isInvalid) Diag(Tok, diag::ext_auto_storage_class) << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); - } else - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, + } else if (getLangOpts().CPlusPlus1z && + (DS.getTypeSpecType() != DS.TST_unspecified) && + (GetLookAheadToken(1).getKind() == tok::coloncolon)) { + // allow int auto::* mp = &X::i; + DS.SetRangeEnd(Tok.getLocation()); + return; + } else { + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID, Policy); + } } else isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, PrevSpec, DiagID, Policy); @@ -4703,6 +4715,12 @@ if (Diags.hasAllExtensionsSilenced()) D.setExtension(); + // Allo auto as a nested name specifier for a member pointer in C++1z + // i.e. void (auto::*mpf)() = &X::f; + const bool IsAutoTokAllowedAsNestedNameSpecifierForMemberPointer = + Tok.is(tok::kw_auto) && getLangOpts().CPlusPlus1z && + NextToken().is(tok::coloncolon); + // C++ member pointers start with a '::' or a nested-name. // Member pointers get special handling, since there's no place for the // scope spec in the generic path below. @@ -4710,6 +4728,7 @@ (Tok.is(tok::coloncolon) || (Tok.is(tok::identifier) && (NextToken().is(tok::coloncolon) || NextToken().is(tok::less))) || + IsAutoTokAllowedAsNestedNameSpecifierForMemberPointer || Tok.is(tok::annot_cxxscope))) { bool EnteringContext = D.getContext() == Declarator::FileContext || D.getContext() == Declarator::MemberContext; @@ -4862,6 +4881,16 @@ return Loc; } +static bool declSpecTypeContainsAuto(const DeclSpec &DS, Sema &S) { + if (DS.getTypeSpecType() == TST_auto) return true; + if (DS.isTypeRep(DS.getTypeSpecType())) { + ParsedType ParsedTy = DS.getRepAsType(); + QualType QTy = S.GetTypeFromParser(ParsedTy); + return QTy->containsAutoType(); + } + return false; +} + /// ParseDirectDeclarator /// direct-declarator: [C99 6.7.5] /// [C99] identifier @@ -4945,7 +4974,7 @@ NextToken().is(tok::r_paren) && !D.hasGroupingParens() && !Actions.containsUnexpandedParameterPacks(D) && - D.getDeclSpec().getTypeSpecType() != TST_auto)) { + !declSpecTypeContainsAuto(D.getDeclSpec(), Actions))) { SourceLocation EllipsisLoc = ConsumeToken(); if (isPtrOperatorToken(Tok.getKind(), getLangOpts(), D.getContext())) { // The ellipsis was put in the wrong place. Recover, and explain to @@ -5526,6 +5555,24 @@ } while (TryConsumeToken(tok::comma)); } +static bool parameterContainsAbbreviatedTemplateSyntax(Decl *Param) { + if (auto *PVD = dyn_cast(Param)) { + auto ContainedAutos = PVD->getType()->getContainedAutoTypes(); + // If the 'auto' is dependent post-initial-parsing (as opposed to an auto + // containing variable having a dependent initializer, rendering the auto + // dependent), then we know that it signifies an abbreviated template + // syntax. + const bool IsDependentAuto = + !ContainedAutos.size() ? false : [&] { + for (const auto *AT : ContainedAutos) + if (AT->isDependentType()) + return true; + return false; + }(); + return IsDependentAuto; + } + return false; +} /// ParseParameterDeclarationClause - Parse a (possibly empty) parameter-list /// after the opening parenthesis. This function will not parse a K&R-style /// identifier list. @@ -5562,6 +5609,10 @@ ParsedAttributes &FirstArgAttrs, SmallVectorImpl &ParamInfo, SourceLocation &EllipsisLoc) { + + // Track whether this parameter clause contains any abbreviated template + // syntax. + bool ContainsAbbreviatedTemplateSyntax = false; do { // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq // before deciding this was a parameter-declaration-clause. @@ -5631,19 +5682,34 @@ // Inform the actions module about the parameter declarator, so it gets // added to the current scope. Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator); + + ContainsAbbreviatedTemplateSyntax = + ContainsAbbreviatedTemplateSyntax || + parameterContainsAbbreviatedTemplateSyntax(Param); + // Parse the default argument, if any. We parse the default // arguments in all dialects; the semantic analysis in // ActOnParamDefaultArgument will reject the default argument in // C. if (Tok.is(tok::equal)) { SourceLocation EqualLoc = Tok.getLocation(); - + const bool MightBeParsingAnAbbreviatedFunctionTemplate = + /*getLangOpts().CPlusPlus14 &&*/ ContainsAbbreviatedTemplateSyntax || + ParmDeclarator.getContext() == Declarator::PrototypeContext || + ParmDeclarator.getContext() == + Declarator::LambdaExprParameterContext; // Parse the default argument - if (D.getContext() == Declarator::MemberContext) { - // If we're inside a class definition, cache the tokens - // corresponding to the default argument. We'll actually parse - // them when we see the end of the class definition. + if (D.getContext() == Declarator::MemberContext || + MightBeParsingAnAbbreviatedFunctionTemplate) { + // If we're inside a class definition, or potentially parsing an + // abbreviated template, cache the tokens corresponding to the default + // argument. We'll actually parse them when we see the end of the + // class definition, or if no abbreviated template syntax: then at the + // end of this parameter-clause, or if contains an abbreviated + // template parameter: then once the declarator has been semantically + // processed. // FIXME: Can we use a smart pointer for Toks? + DefArgToks = new CachedTokens; SourceLocation ArgStartLoc = NextToken().getLocation(); @@ -5721,6 +5787,38 @@ // If the next token is a comma, consume it and keep reading arguments. } while (TryConsumeToken(tok::comma)); + + // Now parse all default arguments if we are not in a member context and we + // determined that we indeed had no abbreviated template syntax within + // parameters. Abbreviated function template default args must only be parsed + // once we have determined whether we have an explicit TPL or an implicitly + // generated one. This information is crucial when determining the depth of + // any generic lambdas within the default args. For e.g. + // void f(int (*)(int) = [](auto a) { return a; }, auto b = 42); + // f(); + + if (D.getContext() != Declarator::MemberContext && + !ContainsAbbreviatedTemplateSyntax) { + using LateParsedDefaultArgument = Parser::LateParsedDefaultArgument; + SmallVector DefaultArgs; + bool HasUnparsedTokens = false; + for (auto &&PInfo : ParamInfo) { + HasUnparsedTokens = HasUnparsedTokens || PInfo.DefaultArgTokens; + DefaultArgs.emplace_back(PInfo.Param, PInfo.DefaultArgTokens); + } + // Temporarily forget this scope with all the parameters declared within it, + // and use a new scope that has the parameters added in sequentially. Ugh!! + if (HasUnparsedTokens) { + Scope *SavedCurScopeWithParameters = getCurScope(); + const auto CurScopeFlags = getCurScope()->getFlags(); + Actions.CurScope = SavedCurScopeWithParameters->getParent(); + { + ParseScope DefaultArgParsingScope(this, CurScopeFlags); + ParseLexedDefaultArguments(DefaultArgs); + } + Actions.CurScope = SavedCurScopeWithParameters; + } + } } /// [C90] direct-declarator '[' constant-expression[opt] ']' Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -25,6 +25,7 @@ #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaDiagnostic.h" +#include "clang/Sema/Template.h" #include "llvm/ADT/SmallString.h" using namespace clang; @@ -2121,6 +2122,9 @@ AttributeList *AccessAttrs, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject *TemplateDiags) { + + ParsingFunctionDeclarationAbbreviatedTemplateInfo AFTI(Actions); + if (Tok.is(tok::at)) { if (getLangOpts().ObjC1 && NextToken().isObjCAtKeyword(tok::objc_defs)) Diag(Tok, diag::err_at_defs_cxx); Index: lib/Parse/ParseExprCXX.cpp =================================================================== --- lib/Parse/ParseExprCXX.cpp +++ lib/Parse/ParseExprCXX.cpp @@ -20,6 +20,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/Template.h" #include "llvm/Support/ErrorHandling.h" @@ -192,6 +193,19 @@ assert(getLangOpts().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); + if (Tok.is(tok::kw_auto) && getLangOpts().CPlusPlus1z && + NextToken().is(tok::coloncolon)) { + SourceLocation AutoLoc = ConsumeToken(); + SourceLocation ColonColonLoc = ConsumeToken(); + TypeSourceInfo *AutoTSI = Actions.Context.getTrivialTypeSourceInfo( + Actions.getAppropriatelyDependentAutoType(/*HasEllipsis*/ false, + /*Declarator*/ nullptr), + AutoLoc); + SS.Extend(Actions.Context, SourceLocation(), AutoTSI->getTypeLoc(), + ColonColonLoc); + return false; + } + if (Tok.is(tok::annot_cxxscope)) { assert(!LastII && "want last identifier but have already annotated scope"); assert(!MayBePseudoDestructor && "unexpected annot_cxxscope"); @@ -1057,9 +1071,8 @@ // Parse lambda-declarator[opt]. DeclSpec DS(AttrFactory); Declarator D(DS, Declarator::LambdaExprContext); - TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); Actions.PushLambdaScope(); - + ParsingFunctionDeclarationAbbreviatedTemplateInfo AFTI(Actions); TypeResult TrailingReturnType; if (Tok.is(tok::l_paren)) { ParseScope PrototypeScope(this, @@ -1077,14 +1090,9 @@ SmallVector ParamInfo; SourceLocation EllipsisLoc; - if (Tok.isNot(tok::r_paren)) { - Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth); + if (Tok.isNot(tok::r_paren)) ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc); - // For a generic lambda, each 'auto' within the parameter declaration - // clause creates a template type parameter, so increment the depth. - if (Actions.getCurGenericLambda()) - ++CurTemplateDepthTracker; - } + T.consumeClose(); SourceLocation RParenLoc = T.getCloseLocation(); DeclEndLoc = RParenLoc; @@ -1234,9 +1242,16 @@ // it. unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope; ParseScope BodyScope(this, ScopeFlags); - + + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope()); - + // For a generic lambda, each 'auto' within the parameter declaration clause + // creates a template type parameter, so increment the depth. + if (Actions.getAbbreviatedFunctionTemplateInfo() + ->AbbreviatedTemplateParameterList) { + ParseAbbreviatedFunctionTemplateDefaultArgs(D); + ++CurTemplateDepthTracker; + } // Parse compound-statement. if (!Tok.is(tok::l_brace)) { Diag(Tok, diag::err_expected_lambda_body); Index: lib/Parse/ParseTemplate.cpp =================================================================== --- lib/Parse/ParseTemplate.cpp +++ lib/Parse/ParseTemplate.cpp @@ -19,6 +19,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/Template.h" using namespace clang; /// \brief Parse a template declaration, explicit instantiation, or @@ -63,7 +64,7 @@ AttributeList *AccessAttrs) { assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) && "Token does not start a template declaration."); - + ParsingFunctionDeclarationAbbreviatedTemplateInfo AFTI(Actions); // Enter template-parameter scope. ParseScope TemplateParmScope(this, Scope::TemplateParamScope); @@ -1286,6 +1287,34 @@ return R; } +void Parser::ParseAbbreviatedFunctionTemplateDefaultArgs( + Declarator &FunDeclarator) { + assert(FunDeclarator.isFunctionDeclarator()); + assert(Actions.getAbbreviatedFunctionTemplateInfo() + ->AbbreviatedTemplateParameterList); + // Now that we know whether we had to create an abbreviated template parameter + // list, parse the default arguments. + TemplateParameterDepthRAII CurTemplateParameterDepth(TemplateParameterDepth); + // If we didn't have an explicitly provided template parameter list for this + // declarator, then add to the template parameter depth. + if (!Actions.getAbbreviatedFunctionTemplateInfo() + ->ExplicitlyProvidedTemplateParameterList) + ++CurTemplateParameterDepth; + + const auto &FTI = FunDeclarator.getFunctionTypeInfo(); + using LateParsedDefaultArgument = Parser::LateParsedDefaultArgument; + SmallVector DefaultArgs; + + for (unsigned I = 0, E = FTI.NumParams; I != E; ++I) + DefaultArgs.emplace_back(FTI.Params[I].Param, + FTI.Params[I].DefaultArgTokens); + + // Introduce the parameters into scope and parse their default arguments. + ParseScope DefaultArgParsingPrototypeScope( + this, Scope::FunctionPrototypeScope | Scope::FunctionDeclarationScope | + Scope::DeclScope); + ParseLexedDefaultArguments(DefaultArgs); +} void Parser::LateTemplateParserCallback(void *P, LateParsedTemplate &LPT) { ((Parser *)P)->ParseLateTemplatedFuncDef(LPT); } Index: lib/Parse/Parser.cpp =================================================================== --- lib/Parse/Parser.cpp +++ lib/Parse/Parser.cpp @@ -20,6 +20,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/Template.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -57,6 +58,7 @@ Tok.startToken(); Tok.setKind(tok::eof); Actions.CurScope = nullptr; + Actions.ParsingTemplateParameterDepthPtr = &TemplateParameterDepth; NumCachedScopes = 0; ParenCount = BracketCount = BraceCount = 0; CurParsedObjCImpl = nullptr; @@ -832,6 +834,7 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, ParsingDeclSpec &DS, AccessSpecifier AS) { + ParsingFunctionDeclarationAbbreviatedTemplateInfo AFTI(Actions); // Parse the common declaration-specifiers piece. ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_top_level); @@ -880,6 +883,7 @@ ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes())); } + // If the declspec consisted only of 'extern' and we have a string // literal following it, this must be a C++ linkage specifier like // 'extern "C"'. @@ -1031,7 +1035,6 @@ // Enter a scope for the function body. ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); - // Tell the actions module that we have entered a function definition with the // specified Declarator for the function. Decl *Res = TemplateInfo.TemplateParams? @@ -1039,6 +1042,18 @@ *TemplateInfo.TemplateParams, D) : Actions.ActOnStartOfFunctionDef(getCurScope(), D); + TemplateParameterDepthRAII CurTemplateParameterDepth(TemplateParameterDepth); + // If abbreviated template syntax was used to declare a function template then + // add one to the template-parameter-depth. + if (Actions.getAbbreviatedFunctionTemplateInfo() && + Actions.getAbbreviatedFunctionTemplateInfo() + ->AbbreviatedTemplateParameterList) { + ParseAbbreviatedFunctionTemplateDefaultArgs(D); + if (!Actions.getAbbreviatedFunctionTemplateInfo() + ->ExplicitlyProvidedTemplateParameterList) + ++CurTemplateParameterDepth; + } + // Break out of the ParsingDeclarator context before we parse the body. D.complete(Res); Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -104,7 +104,9 @@ CurrentInstantiationScope(nullptr), DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr), CurScope(nullptr), - Ident_super(nullptr), Ident___float128(nullptr) + ParsingTemplateParameterDepthPtr(nullptr), + Ident_super(nullptr), Ident___float128(nullptr), + CurAbbreviatedFunctionTemplateInfo(nullptr) { TUScope = nullptr; @@ -1097,15 +1099,6 @@ return LSI; } -void Sema::RecordParsingTemplateParameterDepth(unsigned Depth) { - if (LambdaScopeInfo *const LSI = getCurLambda()) { - LSI->AutoTemplateParameterDepth = Depth; - return; - } - llvm_unreachable( - "Remove assertion if intentionally called in a non-lambda context."); -} - void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP, const Decl *D, const BlockExpr *blkExpr) { FunctionScopeInfo *Scope = FunctionScopes.pop_back_val(); @@ -1172,8 +1165,8 @@ // an associated template parameter list. LambdaScopeInfo *Sema::getCurGenericLambda() { if (LambdaScopeInfo *LSI = getCurLambda()) { - return (LSI->AutoTemplateParams.size() || - LSI->GLTemplateParameterList) ? LSI : nullptr; + if (LSI->CallOperator->getDescribedFunctionTemplate()) + return LSI; } return nullptr; } Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -2741,17 +2741,24 @@ QualType NewReturnType = cast(NewQType)->getReturnType(); if (OldReturnType != NewReturnType) { // If this function has a deduced return type and has already been - // defined, copy the deduced value from the old declaration. - AutoType *OldAT = Old->getReturnType()->getContainedAutoType(); - if (OldAT && OldAT->isDeduced()) { - New->setType( - SubstAutoType(New->getType(), - OldAT->isDependentType() ? Context.DependentTy - : OldAT->getDeducedType())); - NewQType = Context.getCanonicalType( - SubstAutoType(NewQType, - OldAT->isDependentType() ? Context.DependentTy - : OldAT->getDeducedType())); + // defined, copy the deduced return type from the old declaration. + const bool IsDeducedAutoContainingOldReturnType = [&] { + auto ContainedAutos = Old->getReturnType()->getContainedAutoTypes(); + if (!ContainedAutos.size()) return false; + const bool IsFirstAutoDeduced = ContainedAutos.front()->isDeduced(); + assert([&] { + for (auto *AT : ContainedAutos) + if (AT->isDeduced() != IsFirstAutoDeduced) + return false; + return true; + }() && "All autos must either be deduced or non-deduced"); + return IsFirstAutoDeduced; + }(); + if (IsDeducedAutoContainingOldReturnType) { + assert( + Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType)); + Context.adjustDeducedFunctionResultType(New, OldReturnType); + NewQType = Context.getCanonicalType(New->getType()); } } @@ -4607,6 +4614,15 @@ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType R = TInfo->getType(); + if (D.isFunctionDeclarator() && R->containsAutoType() && + D.isFunctionDeclarationContext()) { + assert(getAbbreviatedFunctionTemplateInfo() && + "Must have abbreviated function template info"); + TInfo = normalizeAbbreviatedTemplateType( + TInfo, TemplateParamLists, D); + R = TInfo->getType(); + } + if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, UPPC_DeclarationType)) D.setInvalidType(); @@ -4922,6 +4938,16 @@ Previous.clear(); } + // 'auto' should not be contained within a typedef declaration - while naked + // 'auto' invalid uses are intercepted earlier when we determine the full-type + // of a declarator, here we can check for any embedded auto uses that sneak + // past that check. + if (TInfo->getType()->containsAutoType() && !D.isInvalidType()) { + Diag(TInfo->getTypeLoc().getBeginLoc(), diag::err_auto_not_allowed) + << /*IsDeclTypeAuto*/false << 9 << TInfo->getTypeLoc().getSourceRange(); + D.setInvalidType(true); + return nullptr; + } DiagnoseFunctionSpecifiers(D.getDeclSpec()); if (D.getDeclSpec().isConstexprSpecified()) @@ -5649,7 +5675,7 @@ // 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().containsPlaceholderType() && R->getContainedAutoType()) + if (D.getDeclSpec().containsPlaceholderType() && R->containsAutoType()) ParsingInitForAutoVars.insert(NewVD); if (D.isInvalidType() || Invalid) { @@ -6973,12 +6999,28 @@ NamedDecl* Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, - MultiTemplateParamsArg TemplateParamLists, + MultiTemplateParamsArg TemplateParamListsRef, bool &AddToScope) { QualType R = TInfo->getType(); + // Create a modifiable copy of the template parameter lists so that we can + // augment it if needed with a TPL created for an abbreviated function + // template. + SmallVector TemplateParamLists; + for (auto *TPL : TemplateParamListsRef) + TemplateParamLists.push_back(TPL); assert(R.getTypePtr()->isFunctionType()); - + auto *const AFTI = getAbbreviatedFunctionTemplateInfo(); + const bool IsAbbreviatedFunctionTemplate = + AFTI && AFTI->AbbreviatedTemplateParameterList; + if (getLangOpts().CPlusPlus && IsAbbreviatedFunctionTemplate) { + // If a TPL was explicitly provided in addition to using abbreviated syntax, + // replace the TPL with the abbreviated augemented one. + if (AFTI->ExplicitlyProvidedTemplateParameterList) + TemplateParamLists.back() = AFTI->AbbreviatedTemplateParameterList; + else + TemplateParamLists.push_back(AFTI->AbbreviatedTemplateParameterList); + } // TODO: consider using NameInfo for diagnostic. DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); @@ -8675,7 +8717,8 @@ ParenListExpr *CXXDirectInit = dyn_cast(Init); // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. - if (TypeMayContainAuto && VDecl->getType()->isUndeducedType()) { + if ((TypeMayContainAuto || VDecl->getType()->containsAutoType()) && + VDecl->getType()->isUndeducedType()) { Expr *DeduceInit = Init; // Initializer could be a C++ direct-initializer. Deduction only works if it // contains exactly one expression. @@ -9172,7 +9215,7 @@ QualType Type = Var->getType(); // C++11 [dcl.spec.auto]p3 - if (TypeMayContainAuto && Type->getContainedAutoType()) { + if (TypeMayContainAuto && Type->containsAutoType()) { Diag(Var->getLocation(), diag::err_auto_var_requires_init) << Var->getDeclName() << Type; Var->setInvalidDecl(); @@ -9773,7 +9816,11 @@ VarDecl *DeducedDecl = nullptr; for (unsigned i = 0, e = Group.size(); i != e; ++i) { if (VarDecl *D = dyn_cast(Group[i])) { - AutoType *AT = D->getType()->getContainedAutoType(); + auto ContainedAutos = D->getType()->getContainedAutoTypes(); + // FVTODO: Currently this only checks if the first contained auto is + // deduced to be the same, we need to check for each deduced auto. + const AutoType *AT = + ContainedAutos.size() ? ContainedAutos.front() : nullptr; // Don't reissue diagnostics when instantiating a template. if (AT && D->isInvalidDecl()) break; Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -8479,11 +8479,18 @@ if (Type.isInvalid()) return nullptr; - + bool Invalid = false; DeclarationNameInfo NameInfo = GetNameFromUnqualifiedId(Name); TypeSourceInfo *TInfo = nullptr; - GetTypeFromParser(Type.get(), &TInfo); + QualType QTy = GetTypeFromParser(Type.get(), &TInfo); + // we can't have using-alias's have 'auto' + if (QTy->containsAutoType()) { + Diag(TInfo->getTypeLoc().getBeginLoc(), diag::err_auto_not_allowed) + << /*IsDeclTypeAuto*/false << 10 << TInfo->getTypeLoc().getSourceRange(); + + return nullptr; + } if (DiagnoseClassNameShadow(CurContext, NameInfo)) return nullptr; @@ -12360,7 +12367,14 @@ SourceLocation Loc = D.getIdentifierLoc(); TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); - + QualType R = TInfo->getType(); + if (D.isFunctionDeclarator() && R->containsAutoType() && + D.isFunctionDeclarationContext()) { + assert(getAbbreviatedFunctionTemplateInfo() && + "Must have abbreviated function template info"); + TInfo = normalizeAbbreviatedTemplateType(TInfo, TemplateParams, D); + R = TInfo->getType(); + } // C++ [class.friend]p1 // A friend of a class is a function or class.... // Note that this sees through typedefs, which is intended. Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -4082,6 +4082,29 @@ // default argument expression appears. ContextRAII SavedContext(*this, FD); LocalInstantiationScope Local(*this); + + FunctionDecl *Pattern = FD->getTemplateInstantiationPattern(); + if (!Pattern) { + // Triggered by explicit specializations - since they do not have an + // instantiation pattern. But since we inherit default arguments from + // the primary template, go digging for it. + + // For e.g. + // template void f4(T, int = 17); + // template<> void f4(int, int); f4(i); + // + assert(FD->isFunctionTemplateSpecialization()); + FunctionTemplateDecl *FTD = FD->getPrimaryTemplate(); + assert(FTD); + Pattern = FTD->getTemplatedDecl(); + } + assert(Pattern); + // Add the instantiated parameters to scope, since we should be able to + // refer to them in an unevaluated context. + addInstantiatedParametersToScope( + FD, + Pattern, + Local, MutiLevelArgList); Result = SubstExpr(UninstExpr, MutiLevelArgList); } if (Result.isInvalid()) Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -16,6 +16,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/Designator.h" @@ -4628,6 +4629,35 @@ InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList); } +bool hasAnyDependentGenericLambdas(ArrayRef Exprs) { + // A generic lambda is dependent if its parameters are not at depth 0 - which + // means the surrounding context needs to be instantiated before it can. + struct GenericLambdaDependencyChecker + : StmtVisitor { + bool IsDependent; + GenericLambdaDependencyChecker() : IsDependent(false) { } + bool VisitLambdaExpr(LambdaExpr *E) { + if (auto *TPL = E->getTemplateParameterList()) + if (TPL->getDepth() != 0) + return IsDependent = true; + return false; + } + bool VisitExpr(Expr *Node) { + /// VisitExpr - Visit all of the children of this expression. + bool IsDependent = false; + for (Stmt::child_range I = Node->children(); I; ++I) + IsDependent |= (*I ? Visit(*I) : IsDependent); + return IsDependent; + } + } GenericLambdaDependencyChecker; + for (auto &&E : Exprs) { + GenericLambdaDependencyChecker.IsDependent = false; + GenericLambdaDependencyChecker.Visit(E); + if (GenericLambdaDependencyChecker.IsDependent) + return true; + } + return false; +} void InitializationSequence::InitializeFrom(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -4658,8 +4688,8 @@ // parenthesized list of expressions. QualType DestType = Entity.getType(); - if (DestType->isDependentType() || - Expr::hasAnyTypeDependentArguments(Args)) { + if (DestType->isDependentType() || Expr::hasAnyTypeDependentArguments(Args) || + hasAnyDependentGenericLambdas(Args)) { SequenceKind = DependentSequence; return; } Index: lib/Sema/SemaLambda.cpp =================================================================== --- lib/Sema/SemaLambda.cpp +++ lib/Sema/SemaLambda.cpp @@ -21,6 +21,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaLambda.h" +#include "clang/Sema/Template.h" using namespace clang; using namespace sema; @@ -222,32 +223,20 @@ } static inline TemplateParameterList * -getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) { - if (LSI->GLTemplateParameterList) - return LSI->GLTemplateParameterList; - - if (LSI->AutoTemplateParams.size()) { - SourceRange IntroRange = LSI->IntroducerRange; - SourceLocation LAngleLoc = IntroRange.getBegin(); - SourceLocation RAngleLoc = IntroRange.getEnd(); - LSI->GLTemplateParameterList = TemplateParameterList::Create( - SemaRef.Context, - /*Template kw loc*/ SourceLocation(), LAngleLoc, - (NamedDecl **)LSI->AutoTemplateParams.data(), - LSI->AutoTemplateParams.size(), RAngleLoc); - } - return LSI->GLTemplateParameterList; +getCurGenericLambdaTemplateParameterList(Sema &SemaRef) { + auto *AFTI = SemaRef.getAbbreviatedFunctionTemplateInfo(); + assert(AFTI); + return AFTI->AbbreviatedTemplateParameterList; } CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange, TypeSourceInfo *Info, bool KnownDependent, - LambdaCaptureDefault CaptureDefault) { + LambdaCaptureDefault CaptureDefault, + const bool IsGenericLambda) { DeclContext *DC = CurContext; while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext())) DC = DC->getParent(); - bool IsGenericLambda = getGenericLambdaTemplateParameterList(getCurLambda(), - *this); // Start constructing the lambda class. CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC, Info, IntroducerRange.getBegin(), @@ -354,10 +343,12 @@ SourceRange IntroducerRange, TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc, - ArrayRef Params) { + ArrayRef Params, + TemplateParameterList *GenericLambdaTPL) { + QualType MethodType = MethodTypeInfo->getType(); - TemplateParameterList *TemplateParams = - getGenericLambdaTemplateParameterList(getCurLambda(), *this); + TemplateParameterList *TemplateParams = GenericLambdaTPL; + // If a lambda appears in a dependent context or is a generic lambda (has // template parameters) and has an 'auto' return type, deduce it to a // dependent type. @@ -843,19 +834,7 @@ bool KnownDependent = false; LambdaScopeInfo *const LSI = getCurLambda(); assert(LSI && "LambdaScopeInfo should be on stack!"); - TemplateParameterList *TemplateParams = - getGenericLambdaTemplateParameterList(LSI, *this); - - if (Scope *TmplScope = CurScope->getTemplateParamParent()) { - // Since we have our own TemplateParams, so check if an outer scope - // has template params, only then are we in a dependent scope. - if (TemplateParams) { - TmplScope = TmplScope->getParent(); - TmplScope = TmplScope ? TmplScope->getTemplateParamParent() : nullptr; - } - if (TmplScope && !TmplScope->decl_empty()) - KnownDependent = true; - } + // Determine the signature of the call operator. TypeSourceInfo *MethodTyInfo; bool ExplicitParams = true; @@ -863,6 +842,8 @@ bool ContainsUnexpandedParameterPack = false; SourceLocation EndLoc; SmallVector Params; + + if (ParamInfo.getNumTypeObjects() == 0) { // C++11 [expr.prim.lambda]p4: // If a lambda-expression does not include a lambda-declarator, it is as @@ -900,6 +881,29 @@ MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope); assert(MethodTyInfo && "no type from lambda-declarator"); + QualType MethodTyQ = MethodTyInfo->getType(); + if (MethodTyQ->containsAutoType()) { + assert(getAbbreviatedFunctionTemplateInfo()); + MethodTyInfo = normalizeAbbreviatedTemplateType( + MethodTyInfo, + MultiTemplateParamsArg(), // Generic lamdas dont't ever have an + // additional template parameter list + ParamInfo + ); + MethodTyQ = MethodTyInfo->getType(); + } + //FVQUESTION: Is this the best way to determine known dependency? + if (Scope *TmplScope = CurScope->getTemplateParamParent()) { + // Since we have our own TemplateParams, so check if an outer scope has + // template params, only then are we in a dependent scope. + if (getCurGenericLambdaTemplateParameterList(*this)) { + TmplScope = TmplScope->getParent(); + TmplScope = TmplScope ? TmplScope->getTemplateParamParent() : nullptr; + } + if (TmplScope && !TmplScope->decl_empty()) + KnownDependent = true; + } + EndLoc = ParamInfo.getSourceRange().getEnd(); ExplicitResultType = FTI.hasTrailingReturnType(); @@ -914,12 +918,16 @@ if (MethodTyInfo->getType()->containsUnexpandedParameterPack()) ContainsUnexpandedParameterPack = true; } - + TemplateParameterList *const GenericLambdaTPL = + getCurGenericLambdaTemplateParameterList(*this); CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, MethodTyInfo, - KnownDependent, Intro.Default); + KnownDependent, Intro.Default, + static_cast(GenericLambdaTPL)); CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range, - MethodTyInfo, EndLoc, Params); + MethodTyInfo, EndLoc, Params, + GenericLambdaTPL); + if (ExplicitParams) CheckCXXDefaultArguments(Method); Index: lib/Sema/SemaStmt.cpp =================================================================== --- lib/Sema/SemaStmt.cpp +++ lib/Sema/SemaStmt.cpp @@ -1781,7 +1781,7 @@ diag::err_non_local_variable_decl_in_for)); // If the type contained 'auto', deduce the 'auto' to 'id'. - if (FirstType->getContainedAutoType()) { + if (FirstType->containsAutoType()) { OpaqueValueExpr OpaqueId(D->getLocation(), Context.getObjCIdType(), VK_RValue); Expr *DeducedInit = &OpaqueId; @@ -2630,9 +2630,9 @@ if (CurCap->ReturnType.isNull()) CurCap->ReturnType = FD->getReturnType(); - AutoType *AT = CurCap->ReturnType->getContainedAutoType(); - assert(AT && "lost auto type from lambda return type"); - if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { + assert(CurCap->ReturnType->containsAutoType() && + "lost auto type from lambda return type"); + if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp)) { FD->setInvalidDecl(); return StmtError(); } @@ -2803,10 +2803,29 @@ /// C++1y [dcl.spec.auto]p6. bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, SourceLocation ReturnLoc, - Expr *&RetExpr, - AutoType *AT) { + Expr *&RetExpr) { TypeLoc OrigResultType = getReturnTypeLoc(FD); QualType Deduced; + QualType CurReturnType = FD->getReturnType(); + assert(CurReturnType->containsAutoType()); + auto CurReturnContainedAutos = CurReturnType->getContainedAutoTypes(); + const bool IsCurReturnTypeDecltypeAuto = + CurReturnContainedAutos.size() == 1 && + CurReturnContainedAutos.front()->isDecltypeAuto(); + + const bool IsDeducedCurReturnType = [&] { + assert(CurReturnContainedAutos.size()); + const bool IsFirstAutoDeduced = + CurReturnContainedAutos.front()->isDeduced(); + assert([&] { + for (auto *AT : CurReturnContainedAutos) + if (AT->isDeduced() != IsFirstAutoDeduced) + return false; + return true; + }() && + "All autos must be either deduced or undeduced!"); + return IsFirstAutoDeduced; + }(); if (RetExpr && isa(RetExpr)) { // If the deduction is for a return statement and the initializer is @@ -2823,7 +2842,7 @@ // 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"); + assert(IsDeducedCurReturnType && "should have deduced to dependent type"); return false; } else if (RetExpr) { // If the deduction is for a return statement and the initializer is @@ -2869,19 +2888,18 @@ // has multiple return statements, the return type is deduced for each return // statement. [...] if the type deduced is not the same in each deduction, // the program is ill-formed. - if (AT->isDeduced() && !FD->isInvalidDecl()) { - AutoType *NewAT = Deduced->getContainedAutoType(); + if (IsDeducedCurReturnType && !FD->isInvalidDecl()) { if (!FD->isDependentContext() && - !Context.hasSameType(AT->getDeducedType(), NewAT->getDeducedType())) { + !Context.hasSameType(FD->getReturnType(), Deduced)) { const LambdaScopeInfo *LambdaSI = getCurLambda(); if (LambdaSI && LambdaSI->HasImplicitReturnType) { Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible) - << NewAT->getDeducedType() << AT->getDeducedType() + << Deduced << CurReturnType << true /*IsLambda*/; } else { Diag(ReturnLoc, diag::err_auto_fn_different_deductions) - << (AT->isDecltypeAuto() ? 1 : 0) - << NewAT->getDeducedType() << AT->getDeducedType(); + << (IsCurReturnTypeDecltypeAuto ? 1 : 0) + << Deduced << CurReturnType; } return true; } @@ -2949,9 +2967,9 @@ // FIXME: Add a flag to the ScopeInfo to indicate whether we're performing // deduction. if (getLangOpts().CPlusPlus14) { - if (AutoType *AT = FnRetType->getContainedAutoType()) { + if (FnRetType->containsAutoType()) { FunctionDecl *FD = cast(CurContext); - if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { + if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp)) { FD->setInvalidDecl(); return StmtError(); } else { Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -470,6 +470,273 @@ return nullptr; } +TemplateTypeParmDecl *Sema::makeTemplateTypeParameter( + ASTContext &Context, const unsigned Depth, const unsigned Position, + const SourceLocation AutoLocStart, const bool IsParameterPack, + const std::string InventedTemplateParamPrefix) { + const unsigned TemplateParameterDepth = Depth; + const unsigned AutoParameterPosition = Position; + + // Create a name for the invented template parameter type. + std::string InventedTemplateParamName = InventedTemplateParamPrefix; + llvm::raw_string_ostream ss(InventedTemplateParamName); + ss << TemplateParameterDepth; + ss << "-" << AutoParameterPosition; + ss.flush(); + + IdentifierInfo &TemplateParamII = + Context.Idents.get(InventedTemplateParamName.c_str()); + + return 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*/ AutoLocStart, + TemplateParameterDepth, + AutoParameterPosition, // our template param index + /* Identifier*/ &TemplateParamII, false, IsParameterPack); +} + +static inline TemplateParameterList * +makeAbbreviatedFunctionTemplateParameterList( + const TemplateParameterList *ExistingTPL, + ArrayRef AutoTemplateParams, + ASTContext &Context) { + + TemplateParameterList *AbbreviatedTPL = nullptr; + + if (AutoTemplateParams.size()) { + SourceLocation LAngleLoc = AutoTemplateParams.front()->getLocation(); + SourceLocation RAngleLoc = AutoTemplateParams.back()->getLocation(); + + // If no TPL has been explicitly provided - create one. + if (!ExistingTPL) { + AbbreviatedTPL = TemplateParameterList::Create( + Context, + /*Template kw loc*/ SourceLocation(), LAngleLoc, + (NamedDecl **) AutoTemplateParams.data(), + AutoTemplateParams.size(), RAngleLoc); + } + else { + // Add the auto-params to the end of the existing TPL. + SmallVector AppendedTemplateParams( + ExistingTPL->begin(), ExistingTPL->end()); + AppendedTemplateParams.append(AutoTemplateParams.begin(), + AutoTemplateParams.end()); + + AbbreviatedTPL = TemplateParameterList::Create( + Context, + /*Template kw loc*/ ExistingTPL->getTemplateLoc(), + ExistingTPL->getLAngleLoc(), + (NamedDecl **)AppendedTemplateParams.data(), + AppendedTemplateParams.size(), ExistingTPL->getRAngleLoc()); + } + } + return AbbreviatedTPL; +} + +// Determine whether this function declarator has a corresponding template +// parameter list, but be careful not to use the template parameter list of a +// parent class. + +TemplateParameterList *Sema::getMatchingTemplateParameterListForDeclarator( + MultiTemplateParamsArg CurTemplateParamLists, + const Declarator &FunDeclarator) { + + // Match up the template parameter lists with the scope specifier, to + // determine whether we have a template parameter list associated with this + // declarator. + bool Invalid = false; + const bool IsFriend = FunDeclarator.getDeclSpec().isFriendSpecified(); + bool IsExplicitSpecialization = false; + + return MatchTemplateParametersToScopeSpecifier( + FunDeclarator.getDeclSpec().getLocStart(), + FunDeclarator.getIdentifierLoc(), FunDeclarator.getCXXScopeSpec(), + const_cast(FunDeclarator).getName().getKind() == + UnqualifiedId::IK_TemplateId + ? const_cast(FunDeclarator).getName().TemplateId + : nullptr, + CurTemplateParamLists, IsFriend, IsExplicitSpecialization, Invalid); +} + +// Determine the depth and index of the first abbreviated auto parameter and +// return the values as a (depth, index) pair. +std::pair +determineDepthAndIndexForFirstAbbreviatedTemplateAuto( + const unsigned CurrentParsingTemplateParameterDepth, + TemplateParameterList *ExplicitlyProvidedTPL) { + + std::pair Result(CurrentParsingTemplateParameterDepth, 0); + if (ExplicitlyProvidedTPL) { + // Since we do have a matching corresponding TPL the depth is the same as its + // depth, and the index shall be its size (i.e. one past the previous index). + Result.first = ExplicitlyProvidedTPL->getDepth(); + Result.second = ExplicitlyProvidedTPL->size(); + } + return Result; +} + +// When an abbreviated template's auto's have been replaced by template type +// parameters, its function parameters were rebuilt and stored within the type +// (and typeloc), therefore re-wire the declarator's function parameters to +// refer to the new parameters and ensure default argument information is +// preserved. +void +syncFunctionDeclaratorParametersWithTypeSourceInfo(Declarator &FunDeclarator, + TypeSourceInfo *FunTSI, Sema &S) { + + TypeLoc MethodTL = FunTSI->getTypeLoc().IgnoreParens(); + + // Move past all the attributes... + while (MethodTL.getTypeLocClass() == MethodTL.Attributed) + MethodTL = MethodTL.getAs().getModifiedLoc(); + + assert([&] { + if (MethodTL.getTypeLocClass() == MethodTL.FunctionProto) + return true; + MethodTL.getTypePtr()->dump(); + llvm::errs() << "TypeLocClass = " << MethodTL.getTypeLocClass() + << "\n"; + return false; + }() && + "We should have a function proto type loc!"); + + FunctionProtoTypeLoc FPTL = MethodTL.getAs(); + const unsigned NumParams = FPTL.getNumParams(); + DeclaratorChunk::FunctionTypeInfo &FTI = FunDeclarator.getFunctionTypeInfo(); + assert(NumParams == FTI.NumParams); + for (unsigned I = 0; I != NumParams; ++I) { + ParmVarDecl *OldParm = cast(FTI.Params[I].Param); + ParmVarDecl *NewParm = FPTL.getParam(I); + if (NewParm && OldParm != NewParm) { + assert(!OldParm->hasUninstantiatedDefaultArg() && + "We can't have an uninstantiated default arg around the time we " + "are normalizing 'auto' syntax"); + assert(!OldParm->getInit() && "Abbreviated templates have their " + "default args parsed after all " + "parameters have been normalized"); + if (OldParm->hasUnparsedDefaultArg()) + NewParm->setUnparsedDefaultArg(); + if (OldParm->hasInheritedDefaultArg()) + NewParm->setHasInheritedDefaultArg(); + FTI.Params[I].Param = NewParm; + } + } +} + +std::vector +Sema::getCorrespondingTemplateTypeParmDeclsForAutoTypes( + const unsigned TemplateParamDepthForAllAutos, + const unsigned TemplateParamIndexForFirstAuto, + ArrayRef ContainedAutoTypeLocs) { + std::vector TemplateTypeParmDecls; + unsigned AutoTemplateTypeParamIndex = TemplateParamIndexForFirstAuto; + for (auto ATL : ContainedAutoTypeLocs) { + const AutoType *AT = ATL.getTypePtr()->getAs(); + + TemplateTypeParmDecl *TyTemplParam = makeTemplateTypeParameter( + Context, TemplateParamDepthForAllAutos, AutoTemplateTypeParamIndex++, + ATL.getLocStart(), AT->containsUnexpandedParameterPack()); + + TemplateTypeParmDecls.push_back(TyTemplParam); + } + return TemplateTypeParmDecls; +} + +std::vector Sema::getTypesFromTemplateTypeParamDecls( + ArrayRef TemplateTypeParmDecls) { + std::vector Types; + for (auto *TTyD : TemplateTypeParmDecls) + Types.push_back(QualType(TTyD->getTypeForDecl(), 0)); + return Types; +} + +TypeSourceInfo * +Sema::normalizeAbbreviatedTemplateType( + TypeSourceInfo *AutoContainingTSI, + MultiTemplateParamsArg CurTemplateParamLists, Declarator &FunDeclarator) { + + auto AllContainedAutoTypeLocs = + Type::getContainedAutoTypeLocs(AutoContainingTSI->getTypeLoc()); + + // Only dependent types need to be converted - non-dependent 'autos' signify + // return type deduction at this stage in their processing. Keep in mind, + // that once the declarator has been completely processed, the return type can + // be deduced to a dependent type - be mindful of this. Don't include the + // 'auto' in the return type of the function being declared since it does not + // get replaced with a template-type-param and is not an abbreviated template + // context. e.g auto fun(auto (*fp)(auto) -> auto*); <-- the first 'auto' + // should not get replaced by a template-type-param + + SmallVector ContainedAutoTypeLocs; + for (AutoTypeLoc TL : AllContainedAutoTypeLocs) + if (TL.getTypePtr()->isDependentType()) + ContainedAutoTypeLocs.push_back(TL); + + auto *AFTI = getAbbreviatedFunctionTemplateInfo(); + assert(AFTI); + if (!ContainedAutoTypeLocs.size() || FunDeclarator.isInvalidType()) + return AutoContainingTSI; + + // When trying to determine the depth and index of the first abbreviated auto + // parameter, we must consider any existing template parameter lists and the + // parser's current TemplateParameterDepth (which is the Depth of the next + // TemplateParameterList that the parser might encounter, not the previously + // encountered one). + + // Consider: template void A::mem_fun(T, auto a); <-- (D=1, I=1) + // template void foo(auto a, T t); <-- (D=0, I=1) + // + + // FVTODO: What to do if this is an explicit specialization, i.e. template<> + // void foo(auto); + + // Check to see if the user provided an explicit TPL along with using + // abbreviated template syntax. + AFTI->ExplicitlyProvidedTemplateParameterList = + getMatchingTemplateParameterListForDeclarator(CurTemplateParamLists, + FunDeclarator); + + unsigned AutoTemplateParameterDepth = 0; + unsigned AutoTemplateTypeParamIndex = 0; + + // Calculate the template parameter depth and index of the first auto within a + // parameter. + std::tie(AutoTemplateParameterDepth, AutoTemplateTypeParamIndex) = + determineDepthAndIndexForFirstAbbreviatedTemplateAuto( + getParsingTemplateParameterDepth(), + AFTI->ExplicitlyProvidedTemplateParameterList); + + std::vector CorrespondingTemplateTypeParmDecls = + getCorrespondingTemplateTypeParmDeclsForAutoTypes( + AutoTemplateParameterDepth, AutoTemplateTypeParamIndex, + ContainedAutoTypeLocs); + + std::vector CorrespondingTemplateParamTypes = + getTypesFromTemplateTypeParamDecls(CorrespondingTemplateTypeParmDecls); + + TypeSourceInfo *AutoReplacedTSI = + replaceEachDependentAutoWithCorrespondingTemplateTypes( + AutoContainingTSI, CorrespondingTemplateParamTypes); + assert(AutoReplacedTSI && "Must be able to transform the auto laced types"); + + // Adjust the DeclaratorChunk::FunctionTypeInfo's parameters to point to the + // new ones that contain template-type parameters instead of auto's + syncFunctionDeclaratorParametersWithTypeSourceInfo(FunDeclarator, + AutoReplacedTSI, *this); + + AFTI->AbbreviatedTemplateParameterList = + makeAbbreviatedFunctionTemplateParameterList( + AFTI->ExplicitlyProvidedTemplateParameterList, + CorrespondingTemplateTypeParmDecls, Context); + return AutoReplacedTSI; +} + ParsedTemplateArgument ParsedTemplateArgument::getTemplatePackExpansion( SourceLocation EllipsisLoc) const { assert(Kind == Template && Index: lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- lib/Sema/SemaTemplateDeduction.cpp +++ lib/Sema/SemaTemplateDeduction.cpp @@ -540,7 +540,8 @@ if (const TemplateTypeParmType *TTP = UPP.first.dyn_cast()) return std::make_pair(TTP->getDepth(), TTP->getIndex()); - + assert(!UPP.first.dyn_cast() && + "We should not be asking for depth and index on variadic auto packs"); return getDepthAndIndex(UPP.first.get()); } @@ -3538,7 +3539,7 @@ // type so that we treat it as a non-deduced context in what follows. bool HasDeducedReturnType = false; if (getLangOpts().CPlusPlus14 && InOverloadResolution && - Function->getReturnType()->getContainedAutoType()) { + Function->getReturnType()->containsAutoType()) { FunctionType = SubstAutoType(FunctionType, Context.DependentTy); HasDeducedReturnType = true; } @@ -3583,21 +3584,6 @@ return TDK_Success; } -/// \brief Given a function declaration (e.g. a generic lambda conversion -/// function) that contains an 'auto' in its result type, substitute it -/// with TypeToReplaceAutoWith. Be careful to pass in the type you want -/// to replace 'auto' with and not the actual result type you want -/// to set the function to. -static inline void -SubstAutoWithinFunctionReturnType(FunctionDecl *F, - QualType TypeToReplaceAutoWith, Sema &S) { - assert(!TypeToReplaceAutoWith->getContainedAutoType()); - QualType AutoResultType = F->getReturnType(); - assert(AutoResultType->getContainedAutoType()); - QualType DeducedResultType = S.SubstAutoType(AutoResultType, - TypeToReplaceAutoWith); - S.Context.adjustDeducedFunctionResultType(F, DeducedResultType); -} /// \brief Given a specialized conversion operator of a generic lambda /// create the corresponding specializations of the call operator and @@ -3619,7 +3605,7 @@ CXXMethodDecl *CallOpGeneric = LambdaClass->getLambdaCallOperator(); QualType CallOpResultType = CallOpGeneric->getReturnType(); const bool GenericLambdaCallOperatorHasDeducedReturnType = - CallOpResultType->getContainedAutoType(); + CallOpResultType->containsAutoType(); FunctionTemplateDecl *CallOpTemplate = CallOpGeneric->getDescribedFunctionTemplate(); @@ -3663,23 +3649,25 @@ // specialization's result type. if (GenericLambdaCallOperatorHasDeducedReturnType && InvokerSpecialized->getReturnType()->isUndeducedType()) { - // Be sure to get the type to replace 'auto' with and not - // the full result type of the call op specialization - // to substitute into the 'auto' of the invoker and conversion - // function. - // For e.g. - // int* (*fp)(int*) = [](auto* a) -> auto* { return a; }; - // We don't want to subst 'int*' into 'auto' to get int**. - - QualType TypeToReplaceAutoWith = CallOpSpecialized->getReturnType() - ->getContainedAutoType() - ->getDeducedType(); - SubstAutoWithinFunctionReturnType(InvokerSpecialized, - TypeToReplaceAutoWith, S); - SubstAutoWithinFunctionReturnType(ConversionSpecialized, - TypeToReplaceAutoWith, S); + // Adjust the return type of the static-invoker and the conversion function. + S.Context.adjustDeducedFunctionResultType( + InvokerSpecialized, CallOpSpecialized->getReturnType()); + // The static invoker needs to remove the const-qualifier that it inherits + // from the member function call operator. + const FunctionProtoType *InvokerFPT = + InvokerSpecialized->getType().getTypePtr()->castAs(); + FunctionProtoType::ExtProtoInfo EPI = InvokerFPT->getExtProtoInfo(); + EPI.TypeQuals = 0; + InvokerSpecialized->setType(S.Context.getFunctionType( + InvokerFPT->getReturnType(), InvokerFPT->getParamTypes(), EPI)); + // The conversion function's return type has to be the same as a pointer to + // the invoker function's type. + QualType InvokerTy = InvokerSpecialized->getType(); + QualType ConversionTy = S.Context.getPointerType(InvokerTy); + S.Context.adjustDeducedFunctionResultType( + ConversionSpecialized, ConversionTy); } - + // Ensure that static invoker doesn't have a const qualifier. // FIXME: When creating the InvokerTemplate in SemaLambda.cpp // do not use the CallOperator's TypeSourceInfo which allows @@ -3687,9 +3675,11 @@ const FunctionProtoType *InvokerFPT = InvokerSpecialized-> getType().getTypePtr()->castAs(); FunctionProtoType::ExtProtoInfo EPI = InvokerFPT->getExtProtoInfo(); - EPI.TypeQuals = 0; - InvokerSpecialized->setType(S.Context.getFunctionType( - InvokerFPT->getReturnType(), InvokerFPT->getParamTypes(), EPI)); + if (EPI.TypeQuals) { + EPI.TypeQuals = 0; + InvokerSpecialized->setType(S.Context.getFunctionType( + InvokerFPT->getReturnType(), InvokerFPT->getParamTypes(), EPI)); + } return Sema::TDK_Success; } /// \brief Deduce template arguments for a templated conversion @@ -3858,62 +3848,381 @@ InOverloadResolution); } +Sema::DeduceAutoResult +Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result) { + return DeduceAutoType(Type->getTypeLoc(), Init, Result); +} + namespace { - /// Substitute the 'auto' type specifier within a type for a given replacement - /// type. - class SubstituteAutoTransform : - public TreeTransform { - QualType Replacement; - public: - SubstituteAutoTransform(Sema &SemaRef, QualType Replacement) - : TreeTransform(SemaRef), - Replacement(Replacement) {} - - QualType TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) { - // If we're building the type pattern to deduce against, don't wrap the - // substituted type in an AutoType. Certain template deduction rules - // apply only when a template type parameter appears directly (and not if - // the parameter is found through desugaring). For instance: - // auto &&lref = lvalue; - // must transform into "rvalue reference to T" not "rvalue reference to - // auto type deduced as T" in order for [temp.deduct.call]p3 to apply. - if (!Replacement.isNull() && isa(Replacement)) { - QualType Result = Replacement; - TemplateTypeParmTypeLoc NewTL = - TLB.push(Result); - NewTL.setNameLoc(TL.getNameLoc()); - return Result; - } else { - bool Dependent = - !Replacement.isNull() && Replacement->isDependentType(); - QualType Result = - SemaRef.Context.getAutoType(Dependent ? QualType() : Replacement, - TL.getTypePtr()->isDecltypeAuto(), - Dependent); - AutoTypeLoc NewTL = TLB.push(Result); - NewTL.setNameLoc(TL.getNameLoc()); - return Result; - } +/// The Auto Transformer can operate in 5 distinct modes (see the +/// AutoTransformMode enum below), while performing the following functions: + +/// 1) Making all autos within a type, dependent, when deducing against a +/// dependent type - for e.g: pair p = pair{}; + +/// 2) Making all autos within a type, variadic, when the declarator encounters +/// an ellipsis - for e.g. void (*fp)(pair...) + +/// 3) Converting all autos into template parameters when normalizing +/// abbreviated function template syntax - but when doing so, only an 'auto' +/// type that started its life as dependent should be normalized, all other +/// 'autos' (such as within the deduced return type of the function) must not be +/// normalized into template parameters, during this transformation. + +/// 4) Converting all autos into template parameters when inventing a function +/// template to deduce the corresponding types of each auto from its +/// initialier-expression - during this transformation, all contained autos must +/// be non-dependent. + +/// 5) Replacing each contained auto with ts deduced type, or a contained +/// variadic auto with a sequence of deduced types. This is the only mode of +/// transformation that does require expansion of packs. + +class SubstituteAutosTransformer + : public TreeTransform { + using inherited = + TreeTransform; + + + ArrayRef CorrespondingTemplateTypes; + const TemplateArgumentList *TemplateArgsPtr; + std::map> + //MapAutoSourceLocationToAutoIndex; + MapAutoIndexToReplacementTypeIndex; + + Optional getMappedAutoIndex(const AutoType *AT) { + auto it = MapAutoIndexToReplacementTypeIndex.find(AT->getIndex()); + if (it != MapAutoIndexToReplacementTypeIndex.end()) + return it->second; + + llvm_unreachable("We should always be able to map an autolocation to an " + "index when transforming it"); + return Optional(); + } + + enum class AutoTransformMode { + MakeDependent, + MakeVariadic, + MakeTemplateParametersForAbbreviatedSyntax, + MakeTemplateParametersForDeduction, + MakeDeduced + }; + AutoTransformMode TransformMode; + +public: + struct MakeVariadicTag {}; + struct MakeDependentTag {}; + struct MakeTemplateParametersForDeductionTag {}; + struct MakeTemplateParametersForAbbreviatedSyntaxTag {}; + struct MakeDeducedTag {}; + + SubstituteAutosTransformer(MakeDependentTag, Sema &SemaRef) + : inherited(SemaRef), + TemplateArgsPtr(nullptr), + TransformMode(AutoTransformMode::MakeDependent) {} + + SubstituteAutosTransformer(MakeVariadicTag, Sema &SemaRef) + : inherited(SemaRef), + TemplateArgsPtr(nullptr), + TransformMode(AutoTransformMode::MakeVariadic) {} + + SubstituteAutosTransformer(MakeTemplateParametersForDeductionTag, + Sema &SemaRef, + ArrayRef TemplateParameters) + : inherited(SemaRef), + CorrespondingTemplateTypes(TemplateParameters), + TemplateArgsPtr(nullptr), + TransformMode(AutoTransformMode::MakeTemplateParametersForDeduction) {} + + SubstituteAutosTransformer(MakeTemplateParametersForAbbreviatedSyntaxTag, + Sema &SemaRef, + ArrayRef TemplateParameters) + : inherited(SemaRef), + CorrespondingTemplateTypes(TemplateParameters), + TemplateArgsPtr(nullptr), + TransformMode( + AutoTransformMode::MakeTemplateParametersForAbbreviatedSyntax) {} + + SubstituteAutosTransformer(Sema &SemaRef, + const TemplateArgumentList &DeducedTemplateArgs) + : inherited(SemaRef), + TemplateArgsPtr(&DeducedTemplateArgs), + TransformMode(AutoTransformMode::MakeDeduced) {} + + bool TryExpandParameterPacks(SourceLocation EllipsisLoc, + SourceRange PatternRange, + ArrayRef Unexpanded, + bool &ShouldExpand, bool &RetainExpansion, + Optional &NumExpansions) { + if (TemplateArgsPtr) { + // If we get here - that means we are replacing each auto pack with a + // sequence of types - so lets just check our assumptions and then return + // success, and ensure the out parameters: ShouldExpand, RetainExpansion + // and NumExpansions are set appropriately. + const auto &TemplArgs = *TemplateArgsPtr; + + assert(Unexpanded.size() && + "Must have unexpanded packs if trying to expand them!"); + assert(TransformMode == AutoTransformMode::MakeDeduced && + "Must be replacing autos with deduced types if about to expand a " + "parameter pack during auto substitution"); + assert(!NumExpansions && "Explicitly substituted packs can not be " + "syntaxctically provided while substituting " + "deduced types back into contained autos"); + + assert([&] { + for (auto &&UPP : Unexpanded) { + if (const AutoType *VAuto = + UPP.first.dyn_cast()) { + if (VAuto->isDependentType()) + return false; + continue; + } + return false; + } + return true; + }() && + "All unexpanded packs must be non-dependent variadic autos, else " + "we would have a dependent unexpanded pack type - and dependent " + "types can not be deduced from their initializer - thus never " + "getting here"); + + const AutoType *FirstAutoTyPack = + Unexpanded.front().first.dyn_cast(); + const int AutoBeingSubstitutedIndex = + *getMappedAutoIndex(FirstAutoTyPack); + assert(AutoBeingSubstitutedIndex < (int)TemplateArgsPtr->size()); + + assert(((AutoBeingSubstitutedIndex - 1 + Unexpanded.size()) <= + (int)TemplateArgsPtr->size()) && + "Each unexpanded pack MUST have its own deduced pack supplied"); + + // All our packs must be in sequence, but they don't all have to be the + // same size, consider: auto (*vp)(V, P2...> ... x) + assert([&] { + for (int I = AutoBeingSubstitutedIndex, + E = AutoBeingSubstitutedIndex + Unexpanded.size(); + I != E; ++I) { + if (TemplArgs[I].getKind() != TemplateArgument::Pack) + return false; + } + return true; + }() && + "All our auto variadic packs must be in sequence, since an " + "ellipsis converts all 'autos' in its declarator into variadics"); + + ShouldExpand = true; + NumExpansions = + TemplArgs[AutoBeingSubstitutedIndex].pack_size(); + RetainExpansion = false; + return false; + } + return ShouldExpand = false; + } + + QualType makeAutoDependent(TypeLocBuilder &TLB, AutoTypeLoc TL) { + assert(TransformMode == AutoTransformMode::MakeDependent); + if (TL.getTypePtr()->isDependentType()) { + TLB.pushFullCopy(TL); + return TL.getType(); } + // If not already dependent, make the dependent variant of auto + assert(TL.getType()->isUndeducedType()); + QualType Result = SemaRef.Context.getAutoType( + QualType(), TL.getTypePtr()->isDecltypeAuto(), /*Dependent*/ true, + TL.getTypePtr()->containsUnexpandedParameterPack(), + TL.getTypePtr()->getIndex()); + AutoTypeLoc NewTL = TLB.push(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; + } - ExprResult TransformLambdaExpr(LambdaExpr *E) { - // Lambdas never need to be transformed. - return E; + QualType makeAutoVariadic(TypeLocBuilder &TLB, AutoTypeLoc TL) { + if (TL.getTypePtr()->containsUnexpandedParameterPack()) { + // Don't substitute for an already variadic 'auto'. + TLB.pushFullCopy(TL); + return TL.getType(); } + const AutoType *ATy = TL.getTypePtr(); + assert(ATy->getDeducedType().isNull()); + QualType AQTyVariadic = SemaRef.Context.getAutoType( + QualType(), false, ATy->isDependentType(), /*IsParameterPack*/ true, + ATy->getIndex()); + + AutoTypeLoc NewTL = TLB.push(AQTyVariadic); + NewTL.setNameLoc(TL.getNameLoc()); + return AQTyVariadic; + } - QualType Apply(TypeLoc TL) { - // Create some scratch storage for the transformed type locations. - // FIXME: We're just going to throw this information away. Don't build it. - TypeLocBuilder TLB; - TLB.reserve(TL.getFullDataSize()); - return TransformType(TLB, TL); + QualType replaceAutoWithTemplateParam(TypeLocBuilder &TLB, AutoTypeLoc TL) { + if (TransformMode == + AutoTransformMode::MakeTemplateParametersForAbbreviatedSyntax && + !TL.getTypePtr()->isDependentType()) { + // Don't substitute for any non-dependent 'auto' when substituting for + // abbreviated syntax within function, since an 'auto' when substituting + // during abbreviated syntax normalization can only be within the + // functions return type and does not denote an abbreviated template + // parameter - but rather return type deduction. + TLB.pushFullCopy(TL); + return TL.getType(); } - }; + + // If we're building the type pattern to deduce against, don't wrap the + // substituted type in an AutoType. Certain template deduction rules apply + // only when a template type parameter appears directly (and not if the + // parameter is found through desugaring). For instance: auto &&lref = + // lvalue; must transform into "rvalue reference to T" not "rvalue + // reference to auto type deduced as T" in order for [temp.deduct.call]p3 to + // apply. + const int AutoBeingSubstitutedIndex = *getMappedAutoIndex(TL.getTypePtr()); + assert(AutoBeingSubstitutedIndex < (int)CorrespondingTemplateTypes.size()); + + QualType Replacement( + CorrespondingTemplateTypes[AutoBeingSubstitutedIndex]); + + assert(isa(Replacement)); + QualType Result = Replacement; + TemplateTypeParmTypeLoc NewTL = TLB.push(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; + } + QualType TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) { + + switch(TransformMode) { + + case AutoTransformMode::MakeDependent: + return makeAutoDependent(TLB, TL); + + case AutoTransformMode::MakeVariadic: + return makeAutoVariadic(TLB, TL); + + case AutoTransformMode::MakeTemplateParametersForDeduction: + assert(!TL.getType()->isDependentType() && + "When inventing a function template to deduce against, the auto's " + "can not be dependent"); + case AutoTransformMode::MakeTemplateParametersForAbbreviatedSyntax: + return replaceAutoWithTemplateParam(TLB, TL); + + case AutoTransformMode::MakeDeduced: + break; + } + // We are replacing each 'auto' within this type, with a corresponding + // deduced type - we also handle variadic autos - each variadic auto gets + // replaced with a sequence of deduced types. + assert(TransformMode == AutoTransformMode::MakeDeduced); + assert(TemplateArgsPtr); + assert(!TL.getTypePtr()->isDependentType()); + + const auto& TemplateArgList = *TemplateArgsPtr; + const AutoType *ATy = TL.getTypePtr(); + const int AutoBeingSubstitutedIndex = *getMappedAutoIndex(TL.getTypePtr()); + assert(AutoBeingSubstitutedIndex < (int)TemplateArgList.size()); + + QualType DeducedType; + const TemplateArgument &TA = TemplateArgList[AutoBeingSubstitutedIndex]; + + if (ATy->containsUnexpandedParameterPack()) { + assert(!ATy->isDecltypeAuto()); + assert(TA.getKind() == TA.Pack); + assert(SemaRef.ArgumentPackSubstitutionIndex > -1 && + SemaRef.ArgumentPackSubstitutionIndex < (int)TA.pack_size()); + const TemplateArgument *PackElement = + TA.pack_begin() + SemaRef.ArgumentPackSubstitutionIndex; + assert(PackElement->getKind() == PackElement->Type); + DeducedType = PackElement->getAsType(); + } else { + assert(TA.getKind() == TA.Type); + DeducedType = TA.getAsType(); + } + assert(!DeducedType->isDependentType()); + assert(!DeducedType->containsUnexpandedParameterPack()); + // Now that we've substituted a deduced type into the 'auto' we will not + // need 'Index' again, so set it to 0. + QualType NewAutoType = SemaRef.Context.getAutoType( + DeducedType, ATy->isDecltypeAuto(), /*IsDependent*/ false, + /*ContainsUnexpandedPack*/ false, /*Index*/0); + + AutoTypeLoc NewTL = TLB.push(NewAutoType); + NewTL.setNameLoc(TL.getNameLoc()); + return NewAutoType; + } + + ExprResult TransformLambdaExpr(LambdaExpr *E) { + // Don't go digging into lambdas + return E; + } + + TypeLoc Apply(TypeLoc TL, TypeLocBuilder *TLBPtr = nullptr) { + // Create some scratch storage for the transformed type locations. + TypeLocBuilder TLBStack; + TypeLocBuilder &TLB = TLBPtr ? *TLBPtr : TLBStack; + TLB.reserve(TL.getFullDataSize()); + + MapAutoIndexToReplacementTypeIndex.clear(); + if (TransformMode != AutoTransformMode::MakeVariadic && + TransformMode != AutoTransformMode::MakeDependent) { + // Map each auto's unique index to a sequential index that identifies its + // replacement. + int Idx = 0; + for (auto &&ATL : Type::getContainedAutoTypeLocs(TL)) { + if (TransformMode != + AutoTransformMode::MakeTemplateParametersForAbbreviatedSyntax || + ATL.getType()->isDependentType()) { + const unsigned AIdx = ATL.getTypePtr()->getIndex(); + assert(MapAutoIndexToReplacementTypeIndex.find(AIdx) == + MapAutoIndexToReplacementTypeIndex.end() && + "Each Auto must be unique!"); + MapAutoIndexToReplacementTypeIndex[AIdx] = Idx++; + } + } + assert(Idx != 0); + } + QualType Ty = TransformType(TLB, TL); + if (Ty.isNull()) + return TypeLoc(); + + return TLB.getTypeSourceInfo(SemaRef.Context, Ty)->getTypeLoc(); + } + + TypeSourceInfo *Apply(TypeSourceInfo *TSI) { + TypeLoc OldTL = TSI->getTypeLoc(); + // Create some scratch storage for the transformed type locations. + TypeLocBuilder TLB; + TypeLoc NewTL = Apply(OldTL, &TLB); + if (NewTL.getType().isNull()) + return nullptr; + return TLB.getTypeSourceInfo(SemaRef.Context, NewTL.getType()); + } +}; } -Sema::DeduceAutoResult -Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result) { - return DeduceAutoType(Type->getTypeLoc(), Init, Result); +TypeSourceInfo *Sema::replaceEachDependentAutoWithCorrespondingTemplateTypes( + TypeSourceInfo *TSIWithAuto, + ArrayRef CorrespondingTemplateParamTypes) { + return SubstituteAutosTransformer( + SubstituteAutosTransformer:: + MakeTemplateParametersForAbbreviatedSyntaxTag(), + *this, CorrespondingTemplateParamTypes).Apply(TSIWithAuto); +} + +TypeSourceInfo * +Sema::makeAllContainedAutosVariadic(TypeSourceInfo *TSIWithAuto) { + return SubstituteAutosTransformer( + SubstituteAutosTransformer::MakeVariadicTag(), + *this).Apply(TSIWithAuto); +} + +TypeSourceInfo * +Sema::makeAllContainedAutosDependent(TypeSourceInfo *TSIWithAuto) { + return SubstituteAutosTransformer( + SubstituteAutosTransformer:: + MakeDependentTag(), + *this).Apply(TSIWithAuto); +} + +QualType Sema::makeAllContainedAutosDependent(QualType AutoContainingType) { + auto *TSI = Context.getTrivialTypeSourceInfo(AutoContainingType); + return makeAllContainedAutosDependent(TSI)->getType(); } /// \brief Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6) @@ -3924,15 +4233,19 @@ /// deduced type. Sema::DeduceAutoResult Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) { + if (Init->getType()->isNonOverloadPlaceholderType()) { ExprResult NonPlaceholder = CheckPlaceholderExpr(Init); if (NonPlaceholder.isInvalid()) return DAR_FailedAlreadyDiagnosed; Init = NonPlaceholder.get(); } - + if (Init->isTypeDependent() || Type.getType()->isDependentType()) { - Result = SubstituteAutoTransform(*this, Context.DependentTy).Apply(Type); + using MakeDependentTag = SubstituteAutosTransformer::MakeDependentTag; + Result = SubstituteAutosTransformer(MakeDependentTag(), *this) + .Apply(Type) + .getType(); assert(!Result.isNull() && "substituting DependentTy can't fail"); return DAR_Succeeded; } @@ -3950,70 +4263,136 @@ QualType Deduced = BuildDecltypeType(Init, Init->getLocStart(), false); // FIXME: Support a non-canonical deduced type for 'auto'. Deduced = Context.getCanonicalType(Deduced); - Result = SubstituteAutoTransform(*this, Deduced).Apply(Type); + // FVQUESTION: Why do a transform here? is it to hold on to attributes? + TemplateArgument TArg[] = {TemplateArgument(Deduced)}; + TemplateArgumentList TemplArgList(TemplateArgumentList::OnStack, TArg, 1); + Result = + SubstituteAutosTransformer(*this, TemplArgList) + .Apply(Type) + .getType(); if (Result.isNull()) return DAR_FailedAlreadyDiagnosed; return DAR_Succeeded; } } - SourceLocation Loc = Init->getExprLoc(); - LocalInstantiationScope InstScope(*this); + SourceLocation InitLoc = Init->getExprLoc(); + + auto ContainedAutoTypeLocs = Type::getContainedAutoTypeLocs(Type); + + if (!ContainedAutoTypeLocs.size()) { + assert(getDiagnostics().hasErrorOccurred()); + return DAR_Failed; + } - // Build template void Func(FuncParam); - TemplateTypeParmDecl *TemplParam = - TemplateTypeParmDecl::Create(Context, nullptr, SourceLocation(), Loc, 0, 0, - nullptr, false, false); - QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0); - NamedDecl *TemplParamPtr = TemplParam; - FixedSizeTemplateParameterList<1> TemplateParams(Loc, Loc, &TemplParamPtr, - Loc); - - QualType FuncParam = SubstituteAutoTransform(*this, TemplArg).Apply(Type); - assert(!FuncParam.isNull() && - "substituting template parameter for 'auto' failed"); - - // Deduce type of TemplParam in Func(Init) - SmallVector Deduced; - Deduced.resize(1); + // Invent a function template to deduce against the initializer... + SourceLocation LAngleLoc = Type.getBeginLoc(); + SourceLocation RAngleLoc = Type.getEndLoc(); + std::vector CorrespondingTemplateTypeParmDecls = + getCorrespondingTemplateTypeParmDeclsForAutoTypes(0, 0, + ContainedAutoTypeLocs); + + TemplateParameterList *InventedFuncTPL = TemplateParameterList::Create( + Context, + /*Template kw loc*/ SourceLocation(), LAngleLoc, + (NamedDecl **)CorrespondingTemplateTypeParmDecls.data(), + CorrespondingTemplateTypeParmDecls.size(), RAngleLoc); + + std::vector CorrespondingTemplateParamTypes = + getTypesFromTemplateTypeParamDecls(CorrespondingTemplateTypeParmDecls); + + QualType FuncParam = + SubstituteAutosTransformer( + SubstituteAutosTransformer::MakeTemplateParametersForDeductionTag(), + *this, CorrespondingTemplateParamTypes) + .Apply(Type) + .getType(); + + SmallVector DeducedTemplateArguments; + DeducedTemplateArguments.resize(CorrespondingTemplateTypeParmDecls.size()); QualType InitType = Init->getType(); unsigned TDF = 0; - TemplateDeductionInfo Info(Loc); + TemplateDeductionInfo Info(InitLoc); InitListExpr *InitList = dyn_cast(Init); + // Check if we have an auto, auto&, auto&& + const AutoType *SimpleAutoTy = + Type.getType().getNonReferenceType()->getAs(); if (InitList) { + // If the initializer is a brace-enclosed initializer list, the only way + // this deduction works is if we have either a simple auto or auto-ref + // construct or a std::initializer_list<> template-id containing auto. + + // If we have a simple auto, then deduced the type of each element against + // the substituted corresponding template type... + QualType TemplateArgForInitializerList; + if (SimpleAutoTy) + TemplateArgForInitializerList = FuncParam.getNonReferenceType(); + else { + // ... else if it is a std::initializer_list template-id, then obtain its + // template arguments as the type to deduce against each element of our + // initializer list. + if (!isStdInitializerList(FuncParam.getNonReferenceType(), + &TemplateArgForInitializerList)) + return DAR_Failed; + } for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) { - if (DeduceTemplateArgumentByListElement(*this, &TemplateParams, - TemplArg, - InitList->getInit(i), - Info, Deduced, TDF)) + if (DeduceTemplateArgumentByListElement( + *this, InventedFuncTPL, TemplateArgForInitializerList, + InitList->getInit(i), Info, DeducedTemplateArguments, TDF)) return DAR_Failed; } + } else { - if (AdjustFunctionParmAndArgTypesForDeduction(*this, &TemplateParams, - FuncParam, InitType, Init, - TDF)) + QualType AdjFuncParam = FuncParam; + if (AdjustFunctionParmAndArgTypesForDeduction( + *this, InventedFuncTPL, AdjFuncParam, InitType, Init, TDF)) return DAR_Failed; - if (DeduceTemplateArgumentsByTypeMatch(*this, &TemplateParams, FuncParam, - InitType, Info, Deduced, TDF)) + if (DeduceTemplateArgumentsByTypeMatch(*this, InventedFuncTPL, AdjFuncParam, + InitType, Info, + DeducedTemplateArguments, TDF)) return DAR_Failed; } - - if (Deduced[0].getKind() != TemplateArgument::Type) - return DAR_Failed; - - QualType DeducedType = Deduced[0].getAsType(); - - if (InitList) { - DeducedType = BuildStdInitializerList(DeducedType, Loc); - if (DeducedType.isNull()) + for (DeducedTemplateArgument &DTA : DeducedTemplateArguments) { + if (DTA.getKind() != TemplateArgument::Type && + DTA.getKind() != TemplateArgument::Pack) + return DAR_Failed; + if (DTA.getKind() == TemplateArgument::Pack) { + // for (auto && TA : ) + // FVTODO: Check whether all arguments are types.. + } + } + // If we have an initializer list and are deducing against a naked auto, then + // create a std-initializer-list from the deduced type from each element of + // the initializer-list. + if (InitList && SimpleAutoTy) { + assert(DeducedTemplateArguments.size() == 1); + QualType DeducedType = DeducedTemplateArguments.front().getAsType(); + + QualType InitListDeducedType = + BuildStdInitializerList(DeducedType, InitLoc); + if (InitListDeducedType.isNull()) return DAR_FailedAlreadyDiagnosed; + DeducedTemplateArguments[0] = + DeducedTemplateArgument(TemplateArgument(InitListDeducedType)); } + // Convert this to a vector of template arguments, so that array arithmetic + // works when creating the Template arugment list below. + SmallVector TemplateArguments; + for (DeducedTemplateArgument &DTA : DeducedTemplateArguments) + TemplateArguments.push_back(DTA); + + TemplateArgumentList TemplArgList(TemplateArgumentList::OnStack, + TemplateArguments.data(), + TemplateArguments.size()); + + Result = SubstituteAutosTransformer(*this, TemplArgList) + .Apply(Type) + .getType(); - Result = SubstituteAutoTransform(*this, DeducedType).Apply(Type); if (Result.isNull()) return DAR_FailedAlreadyDiagnosed; @@ -4030,18 +4409,33 @@ return DAR_Succeeded; } -QualType Sema::SubstAutoType(QualType TypeWithAuto, - QualType TypeToReplaceAuto) { - return SubstituteAutoTransform(*this, TypeToReplaceAuto). - TransformType(TypeWithAuto); +QualType Sema::SubstAutoType(QualType AutoContainingType, + QualType Replacement) { + if (Replacement->isDependentType()) + return makeAllContainedAutosDependent(AutoContainingType); + auto ContainedAutos = AutoContainingType->getContainedAutoTypes(); + + assert( + ContainedAutos.size() == 1 && + "For now SubstAutoType only works when there is 1 contained auto type"); + assert(!ContainedAutos.front()->containsUnexpandedParameterPack() && + "For now SubstAutoType only works when there is 1 contained auto type " + "that does not contain a variadic auto"); + auto *AutoContainingTSI = + Context.getTrivialTypeSourceInfo(AutoContainingType); + TemplateArgument TArg[] = {TemplateArgument(Replacement)}; + TemplateArgumentList TemplArgList(TemplateArgumentList::OnStack, TArg, 1); + return SubstituteAutosTransformer(*this, TemplArgList) + .Apply(AutoContainingTSI->getTypeLoc()) + .getType(); } - +/* TypeSourceInfo* Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType TypeToReplaceAuto) { - return SubstituteAutoTransform(*this, TypeToReplaceAuto). + return SubstituteAutosTransformer(*this, TypeToReplaceAuto). TransformType(TypeWithAuto); } - +*/ void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) { if (isa(Init)) Diag(VDecl->getLocation(), Index: lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiate.cpp +++ lib/Sema/SemaTemplateInstantiate.cpp @@ -426,6 +426,7 @@ switch (Active->Kind) { case ActiveTemplateInstantiation::TemplateInstantiation: { Decl *D = Active->Entity; + if (!D) break; if (CXXRecordDecl *Record = dyn_cast(D)) { unsigned DiagID = diag::note_template_member_class_here; if (isa(Record)) @@ -603,7 +604,7 @@ case ActiveTemplateInstantiation::TemplateInstantiation: // An instantiation of an alias template may or may not be a SFINAE // context, depending on what else is on the stack. - if (isa(Active->Entity)) + if (Active->Entity && isa(Active->Entity)) break; // Fall through. case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3062,7 +3062,7 @@ /// Introduce the instantiated function parameters into the local /// instantiation scope, and set the parameter names to those used /// in the template. -static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, +bool Sema::addInstantiatedParametersToScope(FunctionDecl *Function, const FunctionDecl *PatternDecl, LocalInstantiationScope &Scope, const MultiLevelTemplateArgumentList &TemplateArgs) { @@ -3081,7 +3081,7 @@ // it's instantiation-dependent. // FIXME: Updating the type to work around this is at best fragile. if (!PatternDecl->getType()->isDependentType()) { - QualType T = S.SubstType(PatternParam->getType(), TemplateArgs, + QualType T = SubstType(PatternParam->getType(), TemplateArgs, FunctionParam->getLocation(), FunctionParam->getDeclName()); if (T.isNull()) @@ -3097,7 +3097,7 @@ // Expand the parameter pack. Scope.MakeInstantiatedLocalArgPack(PatternParam); Optional NumArgumentsInExpansion - = S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs); + = getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs); assert(NumArgumentsInExpansion && "should only be called when all template arguments are known"); QualType PatternType = @@ -3106,8 +3106,8 @@ ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); FunctionParam->setDeclName(PatternParam->getDeclName()); if (!PatternDecl->getType()->isDependentType()) { - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, Arg); - QualType T = S.SubstType(PatternType, TemplateArgs, + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, Arg); + QualType T = SubstType(PatternType, TemplateArgs, FunctionParam->getLocation(), FunctionParam->getDeclName()); if (T.isNull()) @@ -3147,7 +3147,7 @@ getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true); FunctionDecl *Template = Proto->getExceptionSpecTemplate(); - if (addInstantiatedParametersToScope(*this, Decl, Template, Scope, + if (addInstantiatedParametersToScope(Decl, Template, Scope, TemplateArgs)) { UpdateExceptionSpec(Decl, EST_None); return; @@ -3363,7 +3363,7 @@ if (Function->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDeclaration && !PatternDecl->isInlined() && - !PatternDecl->getReturnType()->getContainedAutoType()) + !PatternDecl->getReturnType()->containsAutoType()) return; if (PatternDecl->isInlined()) { @@ -3415,7 +3415,7 @@ // PushDeclContext because we don't have a scope. Sema::ContextRAII savedContext(*this, Function); - if (addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope, + if (addInstantiatedParametersToScope(Function, PatternDecl, Scope, TemplateArgs)) return; Index: lib/Sema/SemaTemplateVariadic.cpp =================================================================== --- lib/Sema/SemaTemplateVariadic.cpp +++ lib/Sema/SemaTemplateVariadic.cpp @@ -127,6 +127,24 @@ return true; } + bool TraverseAutoType(AutoType *T) { + if (T->containsUnexpandedParameterPack()) { + assert(T->getDeducedType().isNull()); + Unexpanded.push_back(std::make_pair(T, SourceLocation())); + return true; + } + return inherited::TraverseAutoType(T); + } + + bool TraverseAutoTypeLoc(AutoTypeLoc TL) { + if (TL.getTypePtr()->containsUnexpandedParameterPack()) { + assert(TL.getTypePtr()->getDeducedType().isNull()); + Unexpanded.push_back(std::make_pair(TL.getTypePtr(), TL.getNameLoc())); + return true; + } + return inherited::TraverseAutoTypeLoc(TL); + } + /// \brief Suppress traversel into types with location information /// that do not contain unexpanded parameter packs. bool TraverseTypeLoc(TypeLoc TL) { @@ -462,6 +480,11 @@ if (!TSInfo) return true; + // If we have any 'autos' in the template-id - convert the auto to a variadic autos. + // void f(X); + if (TSInfo->getType()->containsAutoType()) + TSInfo = makeAllContainedAutosVariadic(TSInfo); + TypeSourceInfo *TSResult = CheckPackExpansion(TSInfo, EllipsisLoc, None); if (!TSResult) return true; @@ -557,8 +580,18 @@ unsigned Depth = 0, Index = 0; IdentifierInfo *Name; bool IsFunctionParameterPack = false; - - if (const TemplateTypeParmType *TTP + + if (const AutoType *AutoPack = i->first.dyn_cast()) { + // We can not expand auto variadic packs - they can only be expanded + // during deduction from an initializer. Variadic auto packs can end up + // here during substitution within variable templates or when + // instantiating a template function body that contains a variable whose + // placeholder type contains a variadic auto pack - which will then be + // deduced from its initializer. + ShouldExpand = false; + continue; + } + else if (const TemplateTypeParmType *TTP = i->first.dyn_cast()) { Depth = TTP->getDepth(); Index = TTP->getIndex(); Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -688,6 +688,49 @@ state.setCurrentChunkIndex(declarator.getNumTypeObjects()); } +// AutoTypes within parameters using abbreviated function template syntax should +// be dependent, whereas those within variable declarations/return-type for +// deduction should be non-dependent. +// void foo(auto); <-- dependent/abbreviated +// auto foo(); <-- non-dependent (deduced from return-expressions) +// void foo(auto (*)()); <-- dependent/abbreviated +// auto (*foo)() = ... ; <-- non-dependent +// void (*foo)(auto) = ..;<-- non-dependent +QualType Sema::getAppropriatelyDependentAutoType(const bool HasEllipsis, + Declarator *D) { + // Are we declaring a function or a function ptr? Since, in a function + // declaration, auto denotes a template parameter type/abbreviated template, + // but in a function pointer, it denotes a deducible auto as it does within a + // variable template. + + const bool IsDependent = [&] { + // If we are within a function prototype scope, and if the top level + // declarator can not be declaring a function, then auto is intended for + // deduction from an initializer, not signifying an abbreviated template. + if (CurScope + ->isFunctionPrototypeScopeNestedWithinFunctionDeclarationScope()) { + if (D && D->getContext() == D->TrailingReturnContext) { + // These are dependent except if directly within the function + // declaration. + // auto foo(auto ()->auto&) ->auto*; + // <-- the 'auto&' above is dependent, 'auto*' not. + return !CurScope->isFunctionDeclarationScope(); + } + return true; + } + return false; + }(); + // The Index is used to distinguish 'auto's during substitution. + const int CurAutoIndex = + getAbbreviatedFunctionTemplateInfo() + ? getAbbreviatedFunctionTemplateInfo()->CurAutoIndex++ + : 0; + return Context.getAutoType(QualType(), /*decltype(auto)*/ false, + /*dependent*/ IsDependent, + /*IsParameterPack*/ HasEllipsis, + /*Index*/CurAutoIndex); +} + /// \brief Convert the specified declspec to the appropriate type /// object. /// \param state Specifies the declarator containing the declaration specifier @@ -915,7 +958,29 @@ assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "Can't handle qualifiers on typedef names yet!"); - Result = S.GetTypeFromParser(DS.getRepAsType()); + TypeSourceInfo *TSInfo = nullptr; + Result = S.GetTypeFromParser(DS.getRepAsType(), &TSInfo); + + // If the declarator has an ellipsis, check if there are any nonvariadic + // 'auto's in this type - and if so make them variadic. + if (declarator.hasEllipsis()) { + auto AutoVecs = Result->getContainedAutoTypes(); + const bool ContainsNonVariadicAuto = [&] { + for (const AutoType *AT : AutoVecs) + if (!AT->containsUnexpandedParameterPack()) + return true; + return false; + }(); + if (ContainsNonVariadicAuto) { + TSInfo = S.makeAllContainedAutosVariadic(TSInfo); + Result = TSInfo->getType(); + ParsedType ParsedAutoPackTy = S.CreateParsedType(Result, TSInfo); + // FVQUESTION: Is this the best way to do this given the warning in the + // comment of the function UpdateTypeRep? + declarator.getMutableDeclSpec().UpdateTypeRep(ParsedAutoPackTy); + } + } + if (Result.isNull()) declarator.setInvalidType(true); else if (DeclSpec::ProtocolQualifierListTy PQ @@ -996,47 +1061,16 @@ } 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(), /*decltype(auto)*/false, false); - } + case DeclSpec::TST_auto: + Result = S.getAppropriatelyDependentAutoType(declarator.hasEllipsis(), + &declarator); break; case DeclSpec::TST_decltype_auto: - Result = Context.getAutoType(QualType(), - /*decltype(auto)*/true, - /*IsDependent*/ false); + Result = Context.getAutoType(QualType(), + /*decltype(auto)*/ true, + /*IsDependent*/ false, + /*IsParameterPack*/ false, /*Index*/0); break; case DeclSpec::TST_unknown_anytype: @@ -1827,7 +1861,8 @@ return QualType(); } - if (!Class->isDependentType() && !Class->isRecordType()) { + if (!Class->isDependentType() && !Class->isRecordType() && + !Class->isUndeducedType()) { Diag(Loc, diag::err_mempointer_in_nonclass_type) << Class; return QualType(); } @@ -2144,7 +2179,7 @@ // converts to. T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId, &ReturnTypeInfo); - ContainsPlaceholderType = T->getContainedAutoType(); + ContainsPlaceholderType = T->containsAutoType(); break; } @@ -2167,9 +2202,13 @@ llvm_unreachable("Can't specify a type specifier in lambda grammar"); case Declarator::ObjCParameterContext: case Declarator::ObjCResultContext: - case Declarator::PrototypeContext: Error = 0; break; + case Declarator::PrototypeContext: + if (!(SemaRef.getLangOpts().CPlusPlus1z && + D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto)) + Error = 0; + break; case Declarator::LambdaExprParameterContext: if (!(SemaRef.getLangOpts().CPlusPlus14 && D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto)) @@ -2197,7 +2236,9 @@ Error = 7; // Block literal break; case Declarator::TemplateTypeArgContext: - Error = 8; // Template type argument + if (!(SemaRef.getLangOpts().CPlusPlus1z + && D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto)) + Error = 8; // Template type argument break; case Declarator::AliasDeclContext: case Declarator::AliasTemplateContext: @@ -2681,12 +2722,19 @@ } } } - const AutoType *AT = T->getContainedAutoType(); - // Allow arrays of auto if we are a generic lambda parameter. + // Allow arrays of auto if we are in a function prototype as part of + // abbreviated template syntax in C++1z. // i.e. [](auto (&array)[5]) { return array[0]; }; OK - if (AT && D.getContext() != Declarator::LambdaExprParameterContext) { + if (T->containsAutoType() && !D.isPrototypeContext() && + !S.getLangOpts().CPlusPlus1z) { + const bool IsDecltypeAuto = [&] { + auto ContainedAutos = T->getContainedAutoTypes(); + if (ContainedAutos.size() == 1) + return ContainedAutos.front()->isDecltypeAuto(); + return false; + }(); // We've already diagnosed this for decltype(auto). - if (!AT->isDecltypeAuto()) + if (!IsDecltypeAuto) S.Diag(DeclType.Loc, diag::err_illegal_decl_array_of_auto) << getPrintableNameForEntity(Name) << T; T = QualType(); @@ -3033,6 +3081,7 @@ D.setInvalidType(true); } else if (S.isDependentScopeSpecifier(SS) || dyn_cast_or_null(S.computeDeclContext(SS))) { + NestedNameSpecifier *NNS = SS.getScopeRep(); NestedNameSpecifier *NNSPrefix = NNS->getPrefix(); switch (NNS->getKind()) { @@ -3191,7 +3240,56 @@ if (D.getDeclSpec().isConstexprSpecified() && T->isObjectType()) { T.addConst(); } + + // Check whether we have any nsdmi's that require deduction. + if (!D.isInvalidType() && D.getContext() == D.MemberContext && + !D.isFunctionDeclarator()) { + // Static data members can have 'auto' in certain limited circumstances... + if (D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static && + T->containsAutoType()) { + int Error = 1; + switch (cast(S.CurContext)->getTagKind()) { + case TTK_Enum: + llvm_unreachable("unhandled tag kind"); + case TTK_Struct: + Error = 1; /* Struct member */ + break; + case TTK_Union: + Error = 2; /* Union member */ + break; + case TTK_Class: + Error = 3; /* Class member */ + break; + case TTK_Interface: + Error = 4; /* Interface member */ + break; + } + S.Diag(D.getDeclSpec().getLocStart(), diag::err_auto_not_allowed) + << /*IsDeclTypeAuto*/ false << Error + << D.getDeclSpec().getSourceRange(); + D.setInvalidType(true); + } + } + // Make sure that an abbreviated function template is not being declared at + // block scope + if (!D.isInvalidType() && D.isFunctionDeclarator() && + D.getContext() == D.BlockContext) { + auto VQTy = T->getContainedAutoTypes(); + // If we have a dependent auto-type we know we have an auto that signifies + // an abbreviated template. + if (VQTy.size()) { + for (const AutoType *ATy : VQTy) { + if (ATy->isDependentType()) { + S.Diag(D.getLocStart(), + diag::err_template_outside_namespace_or_class_scope); + D.setInvalidType(true); + break; + } + } + } + } + TypeSourceInfo *VariadicAutoContainingTSInfo = nullptr; // If there was an ellipsis in the declarator, the declaration declares a // parameter pack whose type may be a pack expansion type. if (D.hasEllipsis()) { @@ -3201,7 +3299,7 @@ // is a parameter pack (14.5.3). [...] switch (D.getContext()) { case Declarator::PrototypeContext: - case Declarator::LambdaExprParameterContext: + case Declarator::LambdaExprParameterContext: { // C++0x [dcl.fct]p13: // [...] When it is part of a parameter-declaration-clause, the // parameter pack is a function parameter pack (14.5.3). The type T @@ -3211,15 +3309,42 @@ // // We represent function parameter packs as function parameters whose // type is a pack expansion. - if (!T->containsUnexpandedParameterPack()) { - S.Diag(D.getEllipsisLoc(), - diag::err_function_parameter_pack_without_parameter_packs) - << T << D.getSourceRange(); - D.setEllipsisLoc(SourceLocation()); + bool ContainsNonPackAuto = ([T] { + auto AutoVecs = T->getContainedAutoTypes(); + for (const AutoType *AT : AutoVecs) + if (!AT->containsUnexpandedParameterPack()) + return true; + return false; + })(); + + if (!T->containsUnexpandedParameterPack() || ContainsNonPackAuto) { + if (ContainsNonPackAuto) { + TypeSourceInfo *AutoContainingTSInfo = + S.GetTypeSourceInfoForDeclarator(D, T, + /*ReturnTypeInfo?? */ nullptr); + assert(AutoContainingTSInfo); + AutoContainingTSInfo = + S.makeAllContainedAutosVariadic(AutoContainingTSInfo); + T = AutoContainingTSInfo->getType(); + assert(T->containsUnexpandedParameterPack()); + T = Context.getPackExpansionType(T, None); + TypeLocBuilder TLB; + TLB.pushFullCopy(AutoContainingTSInfo->getTypeLoc()); + auto PTL = TLB.push(T); + PTL.setEllipsisLoc(D.getEllipsisLoc()); + VariadicAutoContainingTSInfo = TLB.getTypeSourceInfo(Context, T); + + } else { + S.Diag(D.getEllipsisLoc(), + diag::err_function_parameter_pack_without_parameter_packs) + << T << D.getSourceRange(); + D.setEllipsisLoc(SourceLocation()); + } } else { T = Context.getPackExpansionType(T, None); } break; + } case Declarator::TemplateParamContext: // C++0x [temp.param]p15: // If a template-parameter is a [...] is a parameter-declaration that @@ -3270,7 +3395,9 @@ if (D.isInvalidType()) return Context.getTrivialTypeSourceInfo(T); - return S.GetTypeSourceInfoForDeclarator(D, T, TInfo); + return VariadicAutoContainingTSInfo + ? VariadicAutoContainingTSInfo + : S.GetTypeSourceInfoForDeclarator(D, T, TInfo); } /// GetTypeForDeclarator - Convert the type for the specified @@ -3292,7 +3419,6 @@ return GetFullTypeForDeclarator(state, T, ReturnTypeInfo); } - static void transferARCOwnershipToDeclSpec(Sema &S, QualType &declSpecTy, Qualifiers::ObjCLifetime ownership) { @@ -3823,9 +3949,10 @@ TypeSourceInfo * Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, TypeSourceInfo *ReturnTypeInfo) { + TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T); UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc(); - + // Handle parameter packs whose type is a pack expansion. if (isa(T)) { CurrTL.castAs().setEllipsisLoc(D.getEllipsisLoc()); @@ -5204,7 +5331,8 @@ // that a pointer-to-member type is complete. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { if (const MemberPointerType *MPTy = T->getAs()) { - if (!MPTy->getClass()->isDependentType()) { + if (!MPTy->getClass()->isDependentType() && + !MPTy->getClass()->isUndeducedType()) { RequireCompleteType(Loc, QualType(MPTy->getClass(), 0), 0); assignInheritanceModel(*this, MPTy->getMostRecentCXXRecordDecl()); } Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -827,12 +827,14 @@ /// \brief Build a new C++11 auto type. /// /// By default, builds a new AutoType with the given deduced type. - QualType RebuildAutoType(QualType Deduced, bool IsDecltypeAuto) { + QualType RebuildAutoType(QualType Deduced, bool IsDecltypeAuto, + bool IsParameterPack, unsigned Index) { // Note, IsDependent is always false here: we implicitly convert an 'auto' // which has been deduced to a dependent type into an undeduced 'auto', so // that we'll retry deduction after the transformation. - return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto, - /*IsDependent*/ false); + return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto, + /*IsDependent*/ false, IsParameterPack + , Index); } /// \brief Build a new template specialization type. @@ -3758,7 +3760,8 @@ Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Qs); Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto(), - AutoTy->isDependentType()); + AutoTy->isDependentType(), /*IsParameterPack*/false, + AutoTy->getIndex()); TLB.TypeWasModifiedSafely(Result); } else { // Otherwise, complain about the addition of a qualifier to an @@ -4344,17 +4347,18 @@ OldExpansionTL.getPatternLoc()); if (Result.isNull()) return nullptr; - - Result = RebuildPackExpansionType(Result, + if (ExpectParameterPack) { + Result = RebuildPackExpansionType(Result, OldExpansionTL.getPatternLoc().getSourceRange(), OldExpansionTL.getEllipsisLoc(), NumExpansions); - if (Result.isNull()) - return nullptr; + if (Result.isNull()) + return nullptr; - PackExpansionTypeLoc NewExpansionTL - = TLB.push(Result); - NewExpansionTL.setEllipsisLoc(OldExpansionTL.getEllipsisLoc()); + PackExpansionTypeLoc NewExpansionTL + = TLB.push(Result); + NewExpansionTL.setEllipsisLoc(OldExpansionTL.getEllipsisLoc()); + } NewDI = TLB.getTypeSourceInfo(SemaRef.Context, Result); } else NewDI = getDerived().TransformType(OldDI); @@ -4369,15 +4373,18 @@ OldParm->getInnerLocStart(), OldParm->getLocation(), OldParm->getIdentifier(), - NewDI->getType(), + SemaRef.Context.getAdjustedParameterType(NewDI->getType()), NewDI, OldParm->getStorageClass(), /* DefArg */ nullptr); newParm->setScopeInfo(OldParm->getFunctionScopeDepth(), OldParm->getFunctionScopeIndex() + indexAdjustment); + // FVQUESTION: Must we teach the default transformedLocalDecl to handle + // function parameter packs correctly? Or can we leave that up to the deriving + // class? + getDerived().transformedLocalDecl(OldParm, newParm); return newParm; } - template bool TreeTransform:: TransformFunctionTypeParams(SourceLocation Loc, @@ -4428,7 +4435,7 @@ ParmVarDecl *NewParm = getDerived().TransformFunctionTypeParam(OldParm, indexAdjustment++, - OrigNumExpansions, + NumExpansions, /*ExpectParameterPack=*/false); if (!NewParm) return true; @@ -4446,7 +4453,7 @@ = getDerived().TransformFunctionTypeParam(OldParm, indexAdjustment++, OrigNumExpansions, - /*ExpectParameterPack=*/false); + /*ExpectParameterPack=*/true); if (!NewParm) return true; @@ -4479,13 +4486,11 @@ if (!NewParm) return true; - OutParamTypes.push_back(NewParm->getType()); if (PVars) PVars->push_back(NewParm); continue; } - // Deal with the possibility that we don't have a parameter // declaration for this parameter. QualType OldType = ParamTypes[i]; @@ -4619,7 +4624,6 @@ // and the end of the function-definition, member-declarator, or // declarator. Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals); - ResultType = getDerived().TransformType(TLB, TL.getReturnLoc()); if (ResultType.isNull()) return QualType(); @@ -4962,7 +4966,9 @@ QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced || T->isDependentType()) { - Result = getDerived().RebuildAutoType(NewDeduced, T->isDecltypeAuto()); + Result = getDerived().RebuildAutoType(NewDeduced, T->isDecltypeAuto(), + T->containsUnexpandedParameterPack(), + T->getIndex()); if (Result.isNull()) return QualType(); } @@ -9129,10 +9135,10 @@ LambdaScopeInfo *LSI = getSema().PushLambdaScope(); Sema::FunctionScopeRAII FuncScopeCleanup(getSema()); - + // Transform the template parameters, and add them to the current // instantiation scope. The null case is handled correctly. - LSI->GLTemplateParameterList = getDerived().TransformTemplateParameterList( + TemplateParameterList *NewTPL = getDerived().TransformTemplateParameterList( E->getTemplateParameterList()); // Transform the type of the original lambda's call operator. @@ -9165,14 +9171,16 @@ = getSema().createLambdaClosureType(E->getIntroducerRange(), NewCallOpTSI, /*KnownDependent=*/false, - E->getCaptureDefault()); + E->getCaptureDefault(), + static_cast(NewTPL)); getDerived().transformedLocalDecl(E->getLambdaClass(), Class); // Build the call operator. CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition( Class, E->getIntroducerRange(), NewCallOpTSI, E->getCallOperator()->getLocEnd(), - NewCallOpTSI->getTypeLoc().castAs().getParams()); + NewCallOpTSI->getTypeLoc().castAs().getParams(), + NewTPL); LSI->CallOperator = NewCallOperator; getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -5482,9 +5482,13 @@ case TYPE_AUTO: { QualType Deduced = readType(*Loc.F, Record, Idx); - bool IsDecltypeAuto = Record[Idx++]; - bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; - return Context.getAutoType(Deduced, IsDecltypeAuto, IsDependent); + const bool IsDecltypeAuto = Record[Idx++]; + const unsigned Index = Record[Idx++]; + const bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; + // FVTODO: Should this IsParameterPack below be false? Can we determine what + // the ContainsUnexpandedParameterPack of the type is first? + return Context.getAutoType(Deduced, IsDecltypeAuto, IsDependent, + /*IsParameterPack*/false, Index); } case TYPE_RECORD: { @@ -6030,8 +6034,10 @@ case PREDEF_TYPE_IMAGE3D_ID: T = Context.OCLImage3dTy; break; case PREDEF_TYPE_SAMPLER_ID: T = Context.OCLSamplerTy; break; case PREDEF_TYPE_EVENT_ID: T = Context.OCLEventTy; break; - case PREDEF_TYPE_AUTO_DEDUCT: T = Context.getAutoDeductType(); break; - + case PREDEF_TYPE_AUTO_DEDUCT: + T = Context.getAutoDeductType(); + break; + case PREDEF_TYPE_AUTO_RREF_DEDUCT: T = Context.getAutoRRefDeductType(); break; Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -278,6 +278,7 @@ void ASTTypeWriter::VisitAutoType(const AutoType *T) { Writer.AddTypeRef(T->getDeducedType(), Record); Record.push_back(T->isDecltypeAuto()); + Record.push_back(T->getIndex()); if (T->getDeducedType().isNull()) Record.push_back(T->isDependentType()); Code = TYPE_AUTO; Index: test/CXX/auto/cxx1z-abbreviated-templates.cpp =================================================================== --- /dev/null +++ test/CXX/auto/cxx1z-abbreviated-templates.cpp @@ -0,0 +1,461 @@ +// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -emit-llvm-only %s +// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING +// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS +// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING + +template struct X { }; +namespace multi_declarators { +namespace ns1 { + auto f(auto = 1), g(int), h(auto* = nullptr, auto = 4); + auto f(auto) { } + auto h(auto*, auto) { } + decltype(f())*vp; + decltype(h())*vp2; +} // end ns1 + +namespace ns2 { + auto f(auto = 1), g(int), h(auto* = nullptr); //expected-note{{previous}} + auto f(auto) { } + auto h(auto* = nullptr) { } //expected-error{{redefinition}} + +} // end ns2 +} // end ns multi_declarators + +namespace template_not_allowed_at_block_scope { + +void foo() { + auto f(int); +} +void foo2() { + void f(auto); //expected-error {{templates can only be declared}} +} +} //end ns template_not_allowed_at_block_scope + +namespace default_args { +namespace ns0 { +void f(auto a = decltype(a){}) {} +void g(auto a, auto b, auto c = decltype(a + b + c){}); +int main() { + f(); + g(3, 'a'); +} +} +namespace ns1 { +void g(auto a = decltype(a){}, decltype(a) (*fp)(decltype(a)) = [](auto b) { return b; }); + +template void g(T t, decltype(t) (*fp)(decltype(t))) { fp(t); } + +int main() { + g(); +} + +} // ends ns1 + +namespace ns2 { +void g(int a = decltype(a){}, decltype(a) (*fp)(decltype(a)) = [](auto b) { return b; }, auto c = 3); + +template void g(int a, decltype(a) (*fp)(decltype(a)), T t) { fp(t); } + +int main() { + g(); +} + +} + +namespace ns3 { +auto L = [](int (*fp)(int) = [](auto a) { return a; }, auto b = "abc") { return fp(b[0]); }; +int main() { + L.operator()(); +} + +} +namespace ns4 { +void f(auto a, int (*)(int, decltype(a)) = [](auto b, decltype(a)) { return b;}); + +void f(auto a, int (*fp)(int, decltype(a))) { + fp(3,a); +} + +int main() { + f(3.14); +} +} + +namespace ns5 { +void f(int a, int (*)(int, decltype(a)) = [](auto b, decltype(a)) { return b;}, auto c = decltype(c){}); + +void f(int a, int (*fp)(int, decltype(a)), auto c) { + fp(3,a); +} + +int main() { + f(3); +} +} +namespace class_ns0 { +template struct X { + void f(auto a = decltype(a){}) { } +}; +void foo() { + X().f(); +} +} // end class_ns0 + +namespace class_ns1 { +template struct X { + void f(auto a = decltype(a){}) { } +}; + +template template +void X::f(U u); //expected-error{{must be a definition}} + +void foo() { + X().f(); +} +}//end class_ns1 +namespace class_ns2 { + +template +struct X { + void f(int (*fp)(int) = [](auto a) { return a; }, auto b = decltype(b){}, T = T()) { + fp(3); + fp(b); + } + void g(int (*fp)(int) = [](auto a) { return a; }, auto b = decltype(b){}, T t = T()); + void h(int (*fp)(int) = [](auto a) { return a; }, + auto b = decltype(b){}, T t = T(), auto c = decltype(c){}); +}; + +template +void X::g(int (*fp)(int), auto b, T) { + fp(b); + fp(5); +} + +template template +void X::h(int (*fp)(int), U b, T, auto c) { + fp(b); + fp(5); +} + +void foo() { + X().f(); + X().g(); + X().h(); + +} +} //end class_ns2 +} //end ns default_args + +namespace fun_redecls { +namespace ns0_0 { +void f(auto (*)(auto)->int) { } //expected-note{{previous}} +template void f(int (*)(T)) { } //expected-error{{redefinition}} +} + +namespace ns0 { + +void f(X x) { } + +void eggs() { + X xc; + f(xc); +} + +namespace ns0_1 { + +X(*)(X)> xc; +int f(X(*)(X)> x) { return 0; } +int i = f(xc); + +namespace ns0_1_1 { + +int* foo(auto (*)(auto (*)(auto (*)(auto, auto)))); +int f(char p(double(int, float))); +int *ip = foo(f); + +int* foox(auto(auto(auto(auto, auto)))); +int *ipx = foox(f); + +auto g(auto (auto*)->auto**) -> auto& { } //expected-note{{previous}} +template +auto g(auto (T*)->U**) -> auto& { } //expected-error {{redefinition}} + +} //ns0_1_1 +} // ns0_1 +} // end ns0 + +namespace ns1 { + template void foo(T, auto = 0); //expected-note {{previous}} + template void foo(T, U = 3); //expected-error{{redefinition of default}} + void foo(auto, auto); +} // end ns1 + +namespace ns2 { +void foo(auto i); //expected-note{{previous template declaration}} +template void foo(T = 4); //expected-error{{default arguments cannot be added}} +} + +namespace ns3 { + template auto foo(T, + auto (*)(auto (*)(auto)) = nullptr); //expected-note{{previous}} + template auto foo(T0, + T1 (*)(T2 (*)(T3)) = nullptr); //expected-error{{redefinition of default}} +} + +namespace ns4 { + namespace ns4_1 { + // these are not redeclarations. + auto f(auto (auto) ->auto = 0); + template auto f(T0 (T1) = 0); + + } + namespace ns4_2 { + auto f(auto (auto)->auto* = 0) -> auto&; //expected-note{{previous}} + template auto f(T1* (T0) = 0) ->auto&; //expected-error{{redefinition of default}} + } + // template parameter order matters - a trailing auto is indexed after its parameters! + template auto foo(T, + auto (*)(auto (*)(auto) ->auto*) ->auto = nullptr); + // not a redeclaration because the template parameters are indexed differently + template auto foo(T0, + T1 (*)(T2* (*)(T3)) = nullptr); + +} + +namespace ns5 { + // template parameter order matters - a trailing auto is indexed after its parameters! + // These should be the same declarations + template auto foo(T, + auto (*)(auto (*)(auto) ->auto*) ->auto = nullptr); //expected-note{{previous}} + // not a redeclaration because the template parameters are indexed differently + template auto foo(T0, + T3 (*)(T2* (*)(T1)) = nullptr); //expected-error{{redefinition of default}} + +} + + + +namespace add_to_tpl { + template class TT, class T1> + void foo(T1, auto) { } //expected-note{{previous}} + template class TT, class T1, class T2> + void foo(T1, T2) { } //expected-error{{redefinition}} +} + +namespace cs0 { + +struct Y { + void f(auto); +}; + +template +void Y::f(T t) { } +} // end cs0 + +} //end ns fun_redecls + +namespace friend_decls { + +class Y { + int m; + friend auto f0(auto t) { return t.m; } //expected-note{{previous}} +}; +template +auto f0(T t) { return t.m; } //expected-error{{redefinition}} + +namespace ns1 { + +class Y { + int m; + friend auto f(auto t) { return t.m; } +}; + +int i = f(Y{}); +} + +namespace ns2 { + +template +class Y { + T m{}; + friend auto f2(auto t) { return [=](auto, auto) { return t.m; }; } +}; + +double *dp = f2(Y{})("a", 3.145); + +} +} //end friend_decls + +namespace nested_nns { +template +struct X { T m{}; }; + +auto f(auto auto::*p, auto x) { return x.*p; } + + +int i = f(&X::m, X{}); +double *d = f(&X::m, X{}); +namespace ns1 { + template + struct X { T m; }; + int X::*x2 = &X::m; + + void foo(int X::*); //expected-note {{candidate}} + decltype(foo(&X::m)) *vp0 = nullptr; + void foo2(int auto::*x) { } + decltype(foo2(&X::m)) *vp0_1 = nullptr; + decltype(foo(&X::m)) *vp1 = nullptr; ////expected-error{{no matching}} + + void foov(auto X::* ... p); + static_assert(sizeof(decltype(foov(&X::m, &X::m, &X::m))*),""); + + +} //end ns1 +} +namespace dont_abbreviate_for_auto_in_return_type { + +auto f() -> auto*{ + return (int *)nullptr; +} +int *ip = f(); + +} // end ns dont_abbreviate_for_auto_in_return_type + +namespace generic_lambda_tests { + + void foo() { + auto L = [](auto a) -> decltype(decltype(a)::f()){ + return decltype(a)::f(); + }; + //L(3); + struct A { static void f() { } }; + L(A{}); + } + + namespace ns1 { + auto f(auto t) { + auto L = [=](auto x) { return sizeof(t) + t; }; + return L; + } + auto d = f(2.14)("abc"); + } + namespace ns2 { + template + auto f(auto t) { + auto L = [=](auto x, T) { return sizeof(t) + t; }; + return L; + } + auto d = f(2.14)("abc",(char**)nullptr); + } + +} //end ns generic_lambda_tests + +namespace variadic_tests { +template struct V1 { }; +template struct V2 { }; +template struct VV { }; + +template using FunPtrType = R(*)(Ps...); + +int foo(X ... x2) { return 0; } +int x = foo(X{}, X{}, X{}); +namespace ns0 { +template +int f(V1...v1) { return 0; } + +//template using FunPtrType = R (*)(P); + +int v = f(V1>{},V1>{},V1>{}); + +template +int f2(V1 Ts>...v1) { return 0; } +int v2 = f2(V1>{},V1>{},V1>{}); + +} // end sub variadic_tests::ns0 + +namespace ns1 { + +int foo(VV...> vv) { return 0; } +int x = foo(VV, V1, V1>{}); + +} //end sub variadic_tests::ns1 + +namespace ns2 { + +int foo(int (*...vp)(auto)) { return 0; } +int x = foo(FunPtrType{},FunPtrType{},FunPtrType{}); + +} //end sub ns2 + +namespace ns3 { + +template +int foo(VV, V1...>, VV> ... vs) { return 0; } + +int x0 = foo(VV,V1, V1, V1>, + VV,FunPtrType,FunPtrType>>{}, + VV,V1, V1, V1>, + VV,FunPtrType,FunPtrType>>{}, + VV,V1, V1, V1>, + VV,FunPtrType,FunPtrType>>{} +); + +template +int foo(VV vs) { return 0; } +int x = foo(VV,FunPtrType,FunPtrType>{}); + +} //end sub ns3 + +namespace ns4 { +template void foo(VV...p); // Is the auto a parameterpacktype +decltype(foo(VV{}, VV{}))*vp = nullptr; +namespace ns4_1 { +template struct X { }; +template struct X2 { }; + +int *foo(auto... a) { return nullptr; } +int *ip = foo(X{}, char{}, float{}, double{}, "abc"); + +int *foop(auto* ... a); +int *ip1 = foop("abc", (int*)0, (char*)0, (double*)0); + +int *foox(X ... a); +int *ip1x = foox(X{}, X{}); + +void foon(X2 x2); +decltype(foon(X2{})) *vp = nullptr; + +} +}//end ns4 + +namespace ns5 { +int foo(int (*...vp)(auto)) { return 0; } //expected-note{{candidate}} +int foox(auto (*...vp)(auto)) { return 0; } + +template R f(T) { return R{}; } +int x = foo(f, f); +int x1 = foo(f, f); //expected-error{{no matching}} + +int x0 = foox(f, f); + +} //end ns5 +namespace ns6 { +template struct P { }; +P bar(float, P (*)(int*), P> (*)(double**, int**, short)); +auto f(auto (*)(auto, auto (*)(auto)->P, auto (*)(auto...)->P) -> P) { return; } + +static_assert(sizeof(decltype(f(bar))*), ""); +namespace ns6_1 { +P bar2(float, P (*)(int*), P> (*)(double**, int**, short), + P*, P&); + +template struct X { + template struct Y { + auto f(auto (*)(auto, auto (*)(auto)->P, auto (*)(auto...)->P) -> P, T, U) { return; } + }; +}; +static_assert(sizeof(decltype(X&&>::Y&&>{}.f(bar, P{}, P{}))*), ""); +} //end ns6_1 +} //end ns6 +} //end variadic_tests Index: test/CXX/auto/cxx1z-auto-vars-generalized.cpp =================================================================== --- /dev/null +++ test/CXX/auto/cxx1z-auto-vars-generalized.cpp @@ -0,0 +1,357 @@ +// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -emit-llvm-only %s +// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING +// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS +// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING + +template struct is_same_type { enum { value = 0 }; }; +template struct is_same_type { enum { value = 1 }; }; + +namespace std { + typedef decltype(sizeof(int)) size_t; + + // libc++'s implementation + template + class initializer_list + { + const _E* __begin_; + size_t __size_; + + initializer_list(const _E* __b, size_t __s) + : __begin_(__b), + __size_(__s) + {} + + public: + typedef _E value_type; + typedef const _E& reference; + typedef const _E& const_reference; + typedef size_t size_type; + + typedef const _E* iterator; + typedef const _E* const_iterator; + + initializer_list() : __begin_(nullptr), __size_(0) {} + + size_t size() const {return __size_;} + const _E* begin() const {return __begin_;} + const _E* end() const {return __begin_ + __size_;} + }; +} + + +namespace std_init_list_deduction { + +template struct X { }; + +void foo() { + auto x0 = {X{}, X{}}; + static_assert(is_same_type>>::value, ""); + auto &&x01 = {X{}, X{}}; + static_assert(is_same_type>&&>::value, ""); + + std::initializer_list x1 = {1, 2, 3}; + static_assert(is_same_type>::value, ""); + + std::initializer_list x2 = {X{}, X{}}; + static_assert(is_same_type>>::value, ""); + std::initializer_list> x3 = {X{}, X{}}; + static_assert(is_same_type>>::value, ""); + std::initializer_list> x4 = {X{}, X{}}; + static_assert(is_same_type>>::value, ""); + std::initializer_list> x5 = {X{}, X{}}; //expected-error {{cannot deduce}} +} + + +} + +namespace fun_deduction { +void foo(int, char*); + +auto (*fp1)(int, auto*) = foo; +auto (*fp2)(auto ...) = foo; +auto (*fp3)(int, auto ...) = foo; +void (*fp4)(int, auto ...) = foo; +void (*fp5)(auto, char*, auto ...) = foo; + +auto (&rfp1)(int, auto*) = foo; +auto (&rfp2)(auto ...) = foo; +auto (&rfp3)(int, auto ...) = foo; +void (&rfp4)(int, auto ...) = foo; +void (&rfp5)(auto, char*, auto ...) = foo; +namespace ns1 { + template struct X { }; + + void f(X>); + void (*fp)(X>) = f; +} +namespace ns2 { + +void foo(char, char); +auto (*fp)(auto a, decltype(a)) = foo; + +} +namespace add_auto_post_variadic_fppack { + int* foo(int, float*) { return 0; } + auto (*fp)(int, auto...) -> auto* = foo; + namespace empty_fun_variadic { + void foo(); + auto (*fp)(auto ...) = foo; + } //end ns empty_fun_variadic + namespace ns1 { + template struct V { }; + V, V> v = V,V>{}; + V, V, V...> v2 = V,V,V,V>{}; + } +} + +} + +namespace nested_namespace_specifier_memfun_deduction { + +struct X { + void foo(int, char*); +}; + +auto (auto::*mfp1)(auto...) = &X::foo; + +namespace ns1 { +struct X { + //void foo(); + void foo(int); + X foo(int*, char); + void foo(char); + int m; + int a[10]; +}; +auto (auto::*mpf2)(int*, auto ...) = &X::foo; +void (auto::*mfp1)(char, auto...) = &X::foo; + +auto auto::* x = &X::m; +auto auto::* a = &X::a; + +int auto::x2 = &X::m; //expected-error{{nested name specifier}} + +auto auto::x3 = &X::m; //expected-error{{nested name specifier}} +auto auto::auto::x4 = &X::m; //expected-error{{expected unqualified-id}} + +namespace array_deduction { + +int a[10]; + +auto (*ap)[10] = &a; +auto (auto::*ap2)[10] = &X::a; + + +} + +} // end ns1 + + +namespace ns2 { +template struct X { T t; T f(T); }; +auto X::*ip147 = &X::t; +auto X::*ip = &X::t; +auto (X::*fp)(auto) = &X::f; +auto (X::*fp2)(int) = &X::f; +auto (X::*fp3)(char) = &X::f; //expected-error{{incompatible initializer}} + +struct Y { + int X::*ip = &X::t; //expected-error{{not allowed}} + int (X::*fp)(auto) = &X::f; //expected-error{{not allowed}} + int (X::*fp2)(int) = &X::f; //expected-error{{not allowed}} +}; + +namespace no_nsdmi_deduction { +template +struct X { T m; }; +X xi{}; +struct S { + constexpr static X *const sp = ξ + X *const p = ξ //expected-error{{not allowed}} +}; +} // end ns no_nsdmi_deduction + +} // end ns2 +namespace ns3 { +template +R f(T t) { return R{}; } + +template +R fv(Ts ... t) { return R{}; } + +auto (*(fun()))(auto) { return f; } +auto (*(funv()))(auto...) { return fv; } + + +struct Y { +auto (*(mem_fun()))(auto) { return fun(); } +auto (*(mem_vfun()))(auto...) { return funv(); } + +auto (*(Y::*(mem_ptr_fun()))())(auto) { return &Y::mem_fun; } + +auto (*(Y::*(mem_ptr_fun2()))())(auto...) { return &Y::mem_vfun; } +auto (Y::*(mem_ptr_funv()))(auto...) { return &Y::mem_vfun; } + +auto (*(auto::*(mem_ptr_fun3()))())(auto) { return &Y::mem_fun; } +auto (auto::*(mem_ptr_funv3()))(auto...) { return &Y::mem_vfun; } + +auto (*(fun_array()))[10] { static int arr[10]; return &arr; } +auto (*(fun_array2()))[10] { static char *arr[10]; return &arr; } + int marr1[10]; + char *marr2[10]; +auto (auto::*(mem_fun_array()))[10] { static int arr[10]; return &Y::marr1; } +auto (auto::*(mem_fun_array2()))[10] { static char *arr[10]; return &Y::marr2; } + +//auto (auto::*(mem_ptr_funv2()))(auto...) { return &Y::mem_vfun; } + + +}; +} // end ns3' +} // end ns nested_namespace_specifier_memfun_deduction + + +namespace variadic_deduction { + template struct V { }; + template struct P1 { }; + template struct P2 { }; + namespace ns1 { + int f(V, P2, P2, P2> v); + auto (*vp)(V, P2...>) = f; + static_assert(is_same_type::value, ""); + + decltype(f)* fv(V, P2, P2, P2> v0, V, P2, P2, P2> v1); + + auto (*vp2)(V, P2...> ... x) = fv; + auto (*vp2_0)(V, P2...> ... ) = fv; + + decltype(f)* fv3(V, P2, P2, P2> v0, V, P2, P2, P2> v1); + auto (*vp3)(V, P2...> ... x) = fv3; //expected-error{{incompatible}} + } + namespace ns2 { + template struct V { }; + + template void f(T t) { + V v = V{}; + } + int main() { + f(3.0); + } + } //end ns2 + +} + + +namespace class_template_deduction { +template struct P { }; + +P p = P{}; +P q = P{}; +P q1 = P{}; //expected-error{{incompatible initializer}} +P q2 = P{}; +P,P> pp = P, P>{}; +P,P> pp2 = P, P>{}; +P,P> pp3 = P, P>{}; + +template using alias = int; + +alias a = alias{}; //expected-error{{incompatible}} + + +} //end ns class_template_deduction + + +namespace auto_return { +template struct P { }; +template struct V { }; + P f() { return P{}; } + P f2() { return P{}; } + P f3() { return P{}; } + + V,P...> f4() { return V,P, P>{}; } + namespace ns1 { + template struct X { }; + + X...> foo() { return X, X>{}; } + namespace ns2 { + template struct X { }; + X, X, X> f(); + X, X, X> g(); + X...> (*foo)() = f; + + X...> (*foo3)() = g; //expected-error{{does not contain any unexpanded}} + //template class ... TTs> void bar(X...> (*ts)()) { } + //decltype(bar(g))* vp = nullptr; + X...> (*foo2)() = g; //expected-error{{incompatible}} + } + } +} + +namespace variable_templates { +template +void foo(T t, U u) { } + +template +auto (*fp)(auto, auto) = foo; + +decltype(fp(3, "hello"))* vp = nullptr; + +template struct X { T m; }; + +template +auto auto::*mp = &X::m; + +decltype(mp) *mp2 = nullptr; +namespace ns1 { +template struct V { }; + +template +V, V, V...> v = V,V, V, V, V...>{}; +decltype(v) *ip0; + +template void ft(char*, int*, T); +template auto (*fp)(auto, auto, T) = ft; +decltype(fp)*ip; +} +} + +namespace ill_formed_deduction_ctx { + +using fun_ptr = auto (); //expected-error{{not allowed}} + +template using fun_ptr_t = auto (T); //expected-error{{not allowed}} + +typedef void foo(auto); //expected-error{{not allowed}} + + +void foo(int); +struct Y { + void (*fpy)(auto) = foo; //expected-error{{not allowed}} +}; + +namespace ns1 { +template struct X { + void (*p)(auto) = foo; //expected-error{{not allowed}} +}; + +} + +namespace ns2 { + +template struct X { T t; }; + +struct Y { + X (*foo)() = (X (*)())nullptr; //expected-error {{not allowed}} + X x = X{}; //expected-error{{not allowed}} + X *p = (X*>)nullptr; //expected-error{{not allowed}} +}; + +struct Y2 { + X foo(); + X foo2(); + X foo3(); +}; +} //end ill_formed_deduction_ctx::ns2 +} //end ill_formed_deduction_ctx + + + Index: test/CXX/drs/dr6xx.cpp =================================================================== --- test/CXX/drs/dr6xx.cpp +++ test/CXX/drs/dr6xx.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -DCPP1Z namespace std { struct type_info {}; } @@ -193,9 +193,16 @@ namespace dr625 { // dr625: yes template struct A {}; - A x = A(); // expected-error {{'auto' not allowed in template argument}} expected-error 0-1{{extension}} + A x = A(); +#ifndef CPP1Z + // expected-error@-2 {{'auto' not allowed in template argument}} expected-error@-2 0-1{{extension}} +#endif void f(int); - void (*p)(auto) = f; // expected-error {{'auto' not allowed in function prototype}} expected-error 0-1{{extension}} + void (*p)(auto) = f; +#ifndef CPP1Z + // expected-error@-2 {{'auto' not allowed in function prototype}} expected-error@-2 0-1{{extension}} +#endif + } namespace dr626 { // dr626: yes Index: test/Parser/cxx11-templates.cpp =================================================================== --- test/Parser/cxx11-templates.cpp +++ test/Parser/cxx11-templates.cpp @@ -39,8 +39,6 @@ // because the parameter is in scope in the default argument, so must be // passed to Sema before we reach the ellipsis. template void f(T n = 1 ...); - // expected-warning@-1 {{creates a C-style varargs}} - // expected-note@-2 {{place '...' immediately before declared identifier}} - // expected-note@-3 {{insert ','}} - // expected-error@-4 {{unexpanded parameter pack}} + // expected-error@-1 {{unexpanded parameter pack}} + // expected-error@-2 {{unexpected end of default argument expression}} } Index: test/SemaCXX/cxx1y-deduced-return-type.cpp =================================================================== --- test/SemaCXX/cxx1y-deduced-return-type.cpp +++ test/SemaCXX/cxx1y-deduced-return-type.cpp @@ -96,7 +96,7 @@ return void(); if (false) return; - return 0; // expected-error {{'auto' in return type deduced as 'int' here but deduced as 'void' in earlier return statement}} + return 0; // expected-error {{'auto' containing return type deduced as 'const int' here but deduced as 'const void' in earlier return statement}} } namespace Templates {