From 21ef0fa27b0783ec0bc6aa5b524feb2ec840f952 Mon Sep 17 00:00:00 2001 From: John McCall Date: Thu, 11 Mar 2010 09:03:00 +0000 Subject: [PATCH] Maintain type source information for functions through template instantiation. Based on a patch by Enea Zaffanella! I found a way to reduce some of the redundancy between TreeTransform's "standard" FunctionProtoType transformation and TemplateInstantiator's override, and I killed off the old SubstFunctionType by adding type source info for the last cases where we were creating FunctionDecls without TSI (at least that get passed through template instantiation). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98252 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/Sema.h | 2 + lib/Sema/SemaDecl.cpp | 1 + lib/Sema/SemaDeclCXX.cpp | 16 ++-- lib/Sema/SemaTemplateInstantiate.cpp | 62 +++++++++++++ lib/Sema/SemaTemplateInstantiateDecl.cpp | 111 +++++++++++------------ lib/Sema/TreeTransform.h | 96 ++++++++++++++------ 6 files changed, 193 insertions(+), 95 deletions(-) diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index a94d07a6ac..c9f39e2b99 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3593,6 +3593,8 @@ public: DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC, const MultiLevelTemplateArgumentList &TemplateArgs); + bool CheckInstantiatedParams(llvm::SmallVectorImpl &Params); + // Objective-C declarations. virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 94fcfc6c29..7608199202 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2718,6 +2718,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.getIdentifierLoc(), Name, R, isInline, /*isImplicitlyDeclared=*/false); + NewFD->setTypeSourceInfo(TInfo); isVirtualOkay = true; } else { diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index e694cb470c..830d2e5eef 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2392,22 +2392,26 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { // If a class has no user-declared destructor, a destructor is // declared implicitly. An implicitly-declared destructor is an // inline public member of its class. + QualType Ty = Context.getFunctionType(Context.VoidTy, + 0, 0, false, 0, + /*FIXME:*/false, + false, 0, 0, false, + CC_Default); + DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(ClassType); CXXDestructorDecl *Destructor = CXXDestructorDecl::Create(Context, ClassDecl, - ClassDecl->getLocation(), Name, - Context.getFunctionType(Context.VoidTy, - 0, 0, false, 0, - /*FIXME:*/false, - false, 0, 0, false, - CC_Default), + ClassDecl->getLocation(), Name, Ty, /*isInline=*/true, /*isImplicitlyDeclared=*/true); Destructor->setAccess(AS_public); Destructor->setImplicit(); Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); ClassDecl->addDecl(Destructor); + + // This could be uniqued if it ever proves significant. + Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty)); AddOverriddenMethods(ClassDecl, Destructor); } diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 8f73337e43..19c257d5b7 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -567,6 +567,15 @@ namespace { Sema::OwningExprResult TransformTemplateParmRefExpr(DeclRefExpr *E, NonTypeTemplateParmDecl *D); + /// \brief Transforms a function proto type by performing + /// substitution in the function parameters, possibly adjusting + /// their types and marking default arguments as uninstantiated. + bool TransformFunctionTypeParams(FunctionProtoTypeLoc TL, + llvm::SmallVectorImpl &PTypes, + llvm::SmallVectorImpl &PVars); + + ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm); + /// \brief Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, @@ -859,6 +868,59 @@ Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( } +bool +TemplateInstantiator::TransformFunctionTypeParams(FunctionProtoTypeLoc TL, + llvm::SmallVectorImpl &PTypes, + llvm::SmallVectorImpl &PVars) { + // Create a local instantiation scope for the parameters. + Sema::LocalInstantiationScope + Scope(SemaRef, SemaRef.CurrentInstantiationScope != 0); + + if (TreeTransform:: + TransformFunctionTypeParams(TL, PTypes, PVars)) + return true; + + // Check instantiated parameters. + if (SemaRef.CheckInstantiatedParams(PVars)) + return true; + + return false; +} + +ParmVarDecl * +TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm) { + TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); + TypeSourceInfo *NewDI = getDerived().TransformType(OldDI); + if (!NewDI) + return 0; + + // TODO: do we have to clone this decl if the types match and + // there's no default argument? + + ParmVarDecl *NewParm + = ParmVarDecl::Create(SemaRef.Context, + OldParm->getDeclContext(), + OldParm->getLocation(), + OldParm->getIdentifier(), + NewDI->getType(), + NewDI, + OldParm->getStorageClass(), + /* DefArg */ NULL); + + // Maybe adjust new parameter type. + NewParm->setType(SemaRef.adjustParameterType(NewParm->getType())); + + // Mark the (new) default argument as uninstantiated (if any). + if (OldParm->hasUninstantiatedDefaultArg()) { + Expr *Arg = OldParm->getUninstantiatedDefaultArg(); + NewParm->setUninstantiatedDefaultArg(Arg); + } else if (Expr *Arg = OldParm->getDefaultArg()) + NewParm->setUninstantiatedDefaultArg(Arg); + + SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm); + return NewParm; +} + QualType TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, TemplateTypeParmTypeLoc TL, diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index cf8d38c095..e8bcb8be89 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Lex/Preprocessor.h" @@ -89,7 +90,7 @@ namespace { } // Helper functions for instantiating methods. - QualType SubstFunctionType(FunctionDecl *D, + TypeSourceInfo *SubstFunctionType(FunctionDecl *D, llvm::SmallVectorImpl &Params); bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl); bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl); @@ -797,9 +798,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); llvm::SmallVector Params; - QualType T = SubstFunctionType(D, Params); - if (T.isNull()) + TypeSourceInfo *TInfo = D->getTypeSourceInfo(); + TInfo = SubstFunctionType(D, Params); + if (!TInfo) return 0; + QualType T = TInfo->getType(); // If we're instantiating a local function declaration, put the result // in the owner; otherwise we need to find the instantiated context. @@ -812,7 +815,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), - D->getDeclName(), T, D->getTypeSourceInfo(), + D->getDeclName(), T, TInfo, D->getStorageClass(), D->isInlineSpecified(), D->hasWrittenPrototype()); Function->setLexicalDeclContext(Owner); @@ -932,9 +935,11 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); llvm::SmallVector Params; - QualType T = SubstFunctionType(D, Params); - if (T.isNull()) + TypeSourceInfo *TInfo = D->getTypeSourceInfo(); + TInfo = SubstFunctionType(D, Params); + if (!TInfo) return 0; + QualType T = TInfo->getType(); // Build the instantiated method declaration. CXXRecordDecl *Record = cast(Owner); @@ -947,8 +952,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, SemaRef.Context.getCanonicalType(ClassTy)); Method = CXXConstructorDecl::Create(SemaRef.Context, Record, Constructor->getLocation(), - Name, T, - Constructor->getTypeSourceInfo(), + Name, T, TInfo, Constructor->isExplicit(), Constructor->isInlineSpecified(), false); } else if (CXXDestructorDecl *Destructor = dyn_cast(D)) { @@ -966,12 +970,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, ConvTy); Method = CXXConversionDecl::Create(SemaRef.Context, Record, Conversion->getLocation(), Name, - T, Conversion->getTypeSourceInfo(), + T, TInfo, Conversion->isInlineSpecified(), Conversion->isExplicit()); } else { Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), - D->getDeclName(), T, D->getTypeSourceInfo(), + D->getDeclName(), T, TInfo, D->isStatic(), D->isInlineSpecified()); } @@ -1514,60 +1518,49 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( return false; } -/// \brief Does substitution on the type of the given function, including -/// all of the function parameters. -/// -/// \param D The function whose type will be the basis of the substitution -/// -/// \param Params the instantiated parameter declarations - -/// \returns the instantiated function's type if successful, a NULL -/// type if there was an error. -QualType -TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, - llvm::SmallVectorImpl &Params) { - bool InvalidDecl = false; - - // Substitute all of the function's formal parameter types. - TemplateDeclInstantiator ParamInstantiator(SemaRef, 0, TemplateArgs); - llvm::SmallVector ParamTys; - for (FunctionDecl::param_iterator P = D->param_begin(), - PEnd = D->param_end(); - P != PEnd; ++P) { - if (ParmVarDecl *PInst = ParamInstantiator.VisitParmVarDecl(*P)) { - if (PInst->getType()->isVoidType()) { - SemaRef.Diag(PInst->getLocation(), diag::err_param_with_void_type); +bool +Sema::CheckInstantiatedParams(llvm::SmallVectorImpl &Params) { + bool Invalid = false; + for (unsigned i = 0, i_end = Params.size(); i != i_end; ++i) + if (ParmVarDecl *PInst = Params[i]) { + if (PInst->isInvalidDecl()) + Invalid = true; + else if (PInst->getType()->isVoidType()) { + Diag(PInst->getLocation(), diag::err_param_with_void_type); PInst->setInvalidDecl(); - } else if (SemaRef.RequireNonAbstractType(PInst->getLocation(), - PInst->getType(), - diag::err_abstract_type_in_decl, - Sema::AbstractParamType)) + Invalid = true; + } + else if (RequireNonAbstractType(PInst->getLocation(), + PInst->getType(), + diag::err_abstract_type_in_decl, + Sema::AbstractParamType)) { PInst->setInvalidDecl(); + Invalid = true; + } + } + return Invalid; +} - Params.push_back(PInst); - ParamTys.push_back(PInst->getType()); +TypeSourceInfo* +TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, + llvm::SmallVectorImpl &Params) { + TypeSourceInfo *OldTInfo = D->getTypeSourceInfo(); + assert(OldTInfo && "substituting function without type source info"); + assert(Params.empty() && "parameter vector is non-empty at start"); + TypeSourceInfo *NewTInfo = SemaRef.SubstType(OldTInfo, TemplateArgs, + D->getTypeSpecStartLoc(), + D->getDeclName()); + if (!NewTInfo) + return 0; - if (PInst->isInvalidDecl()) - InvalidDecl = true; - } else - InvalidDecl = true; - } + // Get parameters from the new type info. + TypeLoc NewTL = NewTInfo->getTypeLoc(); + FunctionProtoTypeLoc *NewProtoLoc = cast(&NewTL); + assert(NewProtoLoc && "Missing prototype?"); + for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i) + Params.push_back(NewProtoLoc->getArg(i)); - // FIXME: Deallocate dead declarations. - if (InvalidDecl) - return QualType(); - - const FunctionProtoType *Proto = D->getType()->getAs(); - assert(Proto && "Missing prototype?"); - QualType ResultType - = SemaRef.SubstType(Proto->getResultType(), TemplateArgs, - D->getLocation(), D->getDeclName()); - if (ResultType.isNull()) - return QualType(); - - return SemaRef.BuildFunctionType(ResultType, ParamTys.data(), ParamTys.size(), - Proto->isVariadic(), Proto->getTypeQuals(), - D->getLocation(), D->getDeclName()); + return NewTInfo; } /// \brief Initializes the common fields of an instantiation function diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 17f94193fe..61091cdcc0 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -315,6 +315,21 @@ public: QualType ObjectType = QualType()); #include "clang/AST/TypeLocNodes.def" + /// \brief Transforms the parameters of a function type into the + /// given vectors. + /// + /// The result vectors should be kept in sync; null entries in the + /// variables vector are acceptable. + /// + /// Return true on error. + bool TransformFunctionTypeParams(FunctionProtoTypeLoc TL, + llvm::SmallVectorImpl &PTypes, + llvm::SmallVectorImpl &PVars); + + /// \brief Transforms a single function-type parameter. Return null + /// on error. + ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm); + QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL, QualType ObjectType); @@ -2520,18 +2535,33 @@ QualType TreeTransform::TransformExtVectorType(TypeLocBuilder &TLB, } template -QualType -TreeTransform::TransformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL, - QualType ObjectType) { +ParmVarDecl * +TreeTransform::TransformFunctionTypeParam(ParmVarDecl *OldParm) { + TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); + TypeSourceInfo *NewDI = getDerived().TransformType(OldDI); + if (!NewDI) + return 0; + + if (NewDI == OldDI) + return OldParm; + else + return ParmVarDecl::Create(SemaRef.Context, + OldParm->getDeclContext(), + OldParm->getLocation(), + OldParm->getIdentifier(), + NewDI->getType(), + NewDI, + OldParm->getStorageClass(), + /* DefArg */ NULL); +} + +template +bool TreeTransform:: + TransformFunctionTypeParams(FunctionProtoTypeLoc TL, + llvm::SmallVectorImpl &PTypes, + llvm::SmallVectorImpl &PVars) { FunctionProtoType *T = TL.getTypePtr(); - QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); - if (ResultType.isNull()) - return QualType(); - // Transform the parameters. - llvm::SmallVector ParamTypes; - llvm::SmallVector ParamDecls; for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { ParmVarDecl *OldParm = TL.getArg(i); @@ -2539,24 +2569,11 @@ TreeTransform::TransformFunctionProtoType(TypeLocBuilder &TLB, ParmVarDecl *NewParm; if (OldParm) { - TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); - assert(OldDI->getType() == T->getArgType(i)); + assert(OldParm->getTypeSourceInfo()->getType() == T->getArgType(i)); - TypeSourceInfo *NewDI = getDerived().TransformType(OldDI); - if (!NewDI) - return QualType(); - - if (NewDI == OldDI) - NewParm = OldParm; - else - NewParm = ParmVarDecl::Create(SemaRef.Context, - OldParm->getDeclContext(), - OldParm->getLocation(), - OldParm->getIdentifier(), - NewDI->getType(), - NewDI, - OldParm->getStorageClass(), - /* DefArg */ NULL); + NewParm = getDerived().TransformFunctionTypeParam(OldParm); + if (!NewParm) + return true; NewType = NewParm->getType(); // Deal with the possibility that we don't have a parameter @@ -2567,13 +2584,32 @@ TreeTransform::TransformFunctionProtoType(TypeLocBuilder &TLB, QualType OldType = T->getArgType(i); NewType = getDerived().TransformType(OldType); if (NewType.isNull()) - return QualType(); + return true; } - ParamTypes.push_back(NewType); - ParamDecls.push_back(NewParm); + PTypes.push_back(NewType); + PVars.push_back(NewParm); } + return false; +} + +template +QualType +TreeTransform::TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + QualType ObjectType) { + FunctionProtoType *T = TL.getTypePtr(); + QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); + if (ResultType.isNull()) + return QualType(); + + // Transform the parameters. + llvm::SmallVector ParamTypes; + llvm::SmallVector ParamDecls; + if (getDerived().TransformFunctionTypeParams(TL, ParamTypes, ParamDecls)) + return QualType(); + QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getResultType() || -- 2.40.0