diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 04fbe19a92f0..eb89a0d914e0 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -1137,14 +1137,27 @@ class ImplicitParamDecl : public VarDecl { static bool classofKind(Kind K) { return K == ImplicitParam; } }; -/// ParmVarDecl - Represent a parameter to a function. +/// ParmVarDecl - Represents a parameter to a function. class ParmVarDecl : public VarDecl { + // FIXME: I'm convinced that there's some reasonable way to encode + // these that doesn't require extra storage, but I don't know what + // it is right now. + + /// The number of function parameter scopes enclosing the function + /// parameter scope in which this parameter was declared. + unsigned FunctionScopeDepth : 16; + + /// The number of parameters preceding this parameter in the + /// function parameter scope in which it was declared. + unsigned FunctionScopeIndex : 16; + protected: ParmVarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S, StorageClass SCAsWritten, Expr *DefArg) - : VarDecl(DK, DC, StartLoc, IdLoc, Id, T, TInfo, S, SCAsWritten) { + : VarDecl(DK, DC, StartLoc, IdLoc, Id, T, TInfo, S, SCAsWritten), + FunctionScopeDepth(0), FunctionScopeIndex(0) { assert(ParmVarDeclBits.ObjCDeclQualifier == OBJC_TQ_None); assert(ParmVarDeclBits.HasInheritedDefaultArg == false); assert(ParmVarDeclBits.IsKNRPromoted == false); @@ -1159,6 +1172,22 @@ class ParmVarDecl : public VarDecl { StorageClass S, StorageClass SCAsWritten, Expr *DefArg); + void setScopeInfo(unsigned scopeDepth, unsigned parameterIndex) { + FunctionScopeDepth = scopeDepth; + assert(FunctionScopeDepth == scopeDepth && "truncation!"); + + FunctionScopeIndex = parameterIndex; + assert(FunctionScopeIndex == parameterIndex && "truncation!"); + } + + unsigned getFunctionScopeDepth() const { + return FunctionScopeDepth; + } + + unsigned getFunctionScopeIndex() const { + return FunctionScopeIndex; + } + ObjCDeclQualifier getObjCDeclQualifier() const { return ObjCDeclQualifier(ParmVarDeclBits.ObjCDeclQualifier); } diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h index f70016cbfdbc..6588a1d92dfa 100644 --- a/include/clang/Sema/Scope.h +++ b/include/clang/Sema/Scope.h @@ -16,6 +16,7 @@ #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" namespace clang { @@ -93,6 +94,14 @@ class Scope { /// interrelates with other control flow statements. unsigned short Flags; + /// PrototypeDepth - This is the number of function prototype scopes + /// enclosing this scope, including this scope. + unsigned short PrototypeDepth; + + /// PrototypeIndex - This is the number of parameters currently + /// declared in this scope. + unsigned short PrototypeIndex; + /// FnParent - If this scope has a parent scope that is a function body, this /// pointer is non-null and points to it. This is used for label processing. Scope *FnParent; @@ -196,6 +205,19 @@ class Scope { Scope *getTemplateParamParent() { return TemplateParamParent; } const Scope *getTemplateParamParent() const { return TemplateParamParent; } + /// Returns the number of function prototype scopes in this scope + /// chain. + unsigned getFunctionPrototypeDepth() const { + return PrototypeDepth; + } + + /// Return the number of parameters declared in this function + /// prototype, increasing it by one for the next call. + unsigned getNextFunctionPrototypeIndex() { + assert(isFunctionPrototypeScope()); + return PrototypeIndex++; + } + typedef DeclSetTy::iterator decl_iterator; decl_iterator decl_begin() const { return DeclsInScope.begin(); } decl_iterator decl_end() const { return DeclsInScope.end(); } @@ -302,36 +324,7 @@ class Scope { /// Init - This is used by the parser to implement scope caching. /// - void Init(Scope *Parent, unsigned ScopeFlags) { - AnyParent = Parent; - Depth = AnyParent ? AnyParent->Depth+1 : 0; - Flags = ScopeFlags; - - if (AnyParent) { - FnParent = AnyParent->FnParent; - BreakParent = AnyParent->BreakParent; - ContinueParent = AnyParent->ContinueParent; - ControlParent = AnyParent->ControlParent; - BlockParent = AnyParent->BlockParent; - TemplateParamParent = AnyParent->TemplateParamParent; - } else { - FnParent = BreakParent = ContinueParent = BlockParent = 0; - ControlParent = 0; - TemplateParamParent = 0; - } - - // If this scope is a function or contains breaks/continues, remember it. - if (Flags & FnScope) FnParent = this; - if (Flags & BreakScope) BreakParent = this; - if (Flags & ContinueScope) ContinueParent = this; - if (Flags & ControlScope) ControlParent = this; - if (Flags & BlockScope) BlockParent = this; - if (Flags & TemplateParamScope) TemplateParamParent = this; - DeclsInScope.clear(); - UsingDirectives.clear(); - Entity = 0; - ErrorTrap.reset(); - } + void Init(Scope *parent, unsigned flags); }; } // end namespace clang diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 7dc42b9c5697..07a14d2dca3b 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4527,6 +4527,7 @@ class Sema { DeclarationName Entity); ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs, + int indexAdjustment, llvm::Optional NumExpansions); bool SubstParmTypes(SourceLocation Loc, ParmVarDecl **Params, unsigned NumParams, diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 04d705eb1ab8..c460929c461d 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -21,6 +21,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/ABI.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -50,18 +51,16 @@ static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) { return 0; } -static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) { - assert((isa(MD) || isa(MD)) && - "Passed in decl is not a ctor or dtor!"); +static const FunctionDecl *getStructor(const FunctionDecl *fn) { + if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate()) + return ftd->getTemplatedDecl(); - if (const TemplateDecl *TD = MD->getPrimaryTemplate()) { - MD = cast(TD->getTemplatedDecl()); - - assert((isa(MD) || isa(MD)) && - "Templated decl is not a ctor or dtor!"); - } + return fn; +} - return MD; +static const NamedDecl *getStructor(const NamedDecl *decl) { + const FunctionDecl *fn = dyn_cast_or_null(decl); + return (fn ? getStructor(fn) : decl); } static const unsigned UnknownArity = ~0U; @@ -138,27 +137,75 @@ class CXXNameMangler { ItaniumMangleContext &Context; llvm::raw_ostream &Out; - const CXXMethodDecl *Structor; + /// The "structor" is the top-level declaration being mangled, if + /// that's not a template specialization; otherwise it's the pattern + /// for that specialization. + const NamedDecl *Structor; unsigned StructorType; /// SeqID - The next subsitution sequence number. unsigned SeqID; + class FunctionTypeDepthState { + unsigned Bits; + + enum { InResultTypeMask = 1 }; + + public: + FunctionTypeDepthState() : Bits(0) {} + + /// The number of function types we're inside. + unsigned getDepth() const { + return Bits >> 1; + } + + /// True if we're in the return type of the innermost function type. + bool isInResultType() const { + return Bits & InResultTypeMask; + } + + FunctionTypeDepthState push() { + FunctionTypeDepthState tmp = *this; + Bits = (Bits & ~InResultTypeMask) + 2; + return tmp; + } + + void enterResultType() { + Bits |= InResultTypeMask; + } + + void leaveResultType() { + Bits &= ~InResultTypeMask; + } + + void pop(FunctionTypeDepthState saved) { + assert(getDepth() == saved.getDepth() + 1); + Bits = saved.Bits; + } + + } FunctionTypeDepth; + llvm::DenseMap Substitutions; ASTContext &getASTContext() const { return Context.getASTContext(); } public: - CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_) - : Context(C), Out(Out_), Structor(0), StructorType(0), SeqID(0) { } + CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_, + const NamedDecl *D = 0) + : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0), + SeqID(0) { + // These can't be mangled without a ctor type or dtor type. + assert(!D || (!isa(D) && + !isa(D))); + } CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_, const CXXConstructorDecl *D, CXXCtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), - SeqID(0) { } + SeqID(0) { } CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_, const CXXDestructorDecl *D, CXXDtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), - SeqID(0) { } + SeqID(0) { } #if MANGLE_CHECKER ~CXXNameMangler() { @@ -272,6 +319,8 @@ class CXXNameMangler { void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A); void mangleTemplateParameter(unsigned Index); + + void mangleFunctionParam(const ParmVarDecl *parm); }; } @@ -1473,8 +1522,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { case BuiltinType::Dependent: case BuiltinType::BoundMember: case BuiltinType::UnknownAny: - assert(false && - "Overloaded and dependent types shouldn't get to name mangling"); + llvm_unreachable("mangling a placeholder type"); break; case BuiltinType::ObjCId: Out << "11objc_object"; break; case BuiltinType::ObjCClass: Out << "10objc_class"; break; @@ -1499,13 +1547,22 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, // We should never be mangling something without a prototype. const FunctionProtoType *Proto = cast(T); + // Record that we're in a function type. See mangleFunctionParam + // for details on what we're trying to achieve here. + FunctionTypeDepthState saved = FunctionTypeDepth.push(); + // ::= + - if (MangleReturnType) + if (MangleReturnType) { + FunctionTypeDepth.enterResultType(); mangleType(Proto->getResultType()); + FunctionTypeDepth.leaveResultType(); + } if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) { // ::= v # void Out << 'v'; + + FunctionTypeDepth.pop(saved); return; } @@ -1514,6 +1571,8 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, Arg != ArgEnd; ++Arg) mangleType(*Arg); + FunctionTypeDepth.pop(saved); + // ::= z # ellipsis if (Proto->isVariadic()) Out << 'z'; @@ -2227,6 +2286,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { Out << 'E'; break; + case Decl::ParmVar: + mangleFunctionParam(cast(D)); + break; + case Decl::EnumConstant: { const EnumConstantDecl *ED = cast(D); mangleIntegerLiteral(ED->getType(), ED->getInitVal()); @@ -2388,6 +2451,67 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { } } +/// Mangle an expression which refers to a parameter variable. +/// +/// ::= +/// ::= fp _ # L == 0, I == 0 +/// ::= fp +/// _ # L == 0, I > 0 +/// ::= fL +/// p _ # L > 0, I == 0 +/// ::= fL +/// p +/// _ # L > 0, I > 0 +/// +/// L is the nesting depth of the parameter, defined as 1 if the +/// parameter comes from the innermost function prototype scope +/// enclosing the current context, 2 if from the next enclosing +/// function prototype scope, and so on, with one special case: if +/// we've processed the full parameter clause for the innermost +/// function type, then L is one less. This definition conveniently +/// makes it irrelevant whether a function's result type was written +/// trailing or leading, but is otherwise overly complicated; the +/// numbering was first designed without considering references to +/// parameter in locations other than return types, and then the +/// mangling had to be generalized without changing the existing +/// manglings. +/// +/// I is the zero-based index of the parameter within its parameter +/// declaration clause. Note that the original ABI document describes +/// this using 1-based ordinals. +void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) { + unsigned parmDepth = parm->getFunctionScopeDepth(); + unsigned parmIndex = parm->getFunctionScopeIndex(); + + // Compute 'L'. + // parmDepth does not include the declaring function prototype. + // FunctionTypeDepth does account for that. + assert(parmDepth < FunctionTypeDepth.getDepth()); + unsigned nestingDepth = FunctionTypeDepth.getDepth() - parmDepth; + if (FunctionTypeDepth.isInResultType()) + nestingDepth--; + + if (nestingDepth == 0) { + Out << "fp"; + } else { + Out << "fL" << (nestingDepth - 1) << 'p'; + } + + // Top-level qualifiers. We don't have to worry about arrays here, + // because parameters declared as arrays should already have been + // tranformed to have pointer type. FIXME: apparently these don't + // get mangled if used as an rvalue of a known non-class type? + assert(!parm->getType()->isArrayType() + && "parameter's type is still an array type?"); + mangleQualifiers(parm->getType().getQualifiers()); + + // Parameter index. + if (parmIndex != 0) { + Out << (parmIndex - 1); + } + Out << '_'; +} + void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) { // ::= C1 # complete object constructor // ::= C2 # base object constructor @@ -2794,7 +2918,7 @@ void ItaniumMangleContext::mangleName(const NamedDecl *D, getASTContext().getSourceManager(), "Mangling declaration"); - CXXNameMangler Mangler(*this, Out); + CXXNameMangler Mangler(*this, Out, D); return Mangler.mangle(D); } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 17383c137a25..44818e8c0847 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -961,12 +961,16 @@ void StmtProfiler::VisitDecl(Decl *D) { } if (ParmVarDecl *Parm = dyn_cast(D)) { - // The Itanium C++ ABI uses the type of a parameter when mangling - // expressions that involve function parameters, so we will use the - // parameter's type for establishing function parameter identity. That - // way, our definition of "equivalent" (per C++ [temp.over.link]) - // matches the definition of "equivalent" used for name mangling. + // The Itanium C++ ABI uses the type, scope depth, and scope + // index of a parameter when mangling expressions that involve + // function parameters, so we will use the parameter's type for + // establishing function parameter identity. That way, our + // definition of "equivalent" (per C++ [temp.over.link]) is at + // least as strong as the definition of "equivalent" used for + // name mangling. VisitType(Parm->getType()); + ID.AddInteger(Parm->getFunctionScopeDepth()); + ID.AddInteger(Parm->getFunctionScopeIndex()); return; } diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index e1f0cb660bab..0a670197d7ef 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -8,6 +8,7 @@ add_clang_library(clangSema DelayedDiagnostic.cpp IdentifierResolver.cpp JumpDiagnostics.cpp + Scope.cpp Sema.cpp SemaAccess.cpp SemaAttr.cpp diff --git a/lib/Sema/Scope.cpp b/lib/Sema/Scope.cpp new file mode 100644 index 000000000000..833a59fdceea --- /dev/null +++ b/lib/Sema/Scope.cpp @@ -0,0 +1,57 @@ +//===- Scope.cpp - Lexical scope information --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Scope class, which is used for recording +// information about a lexical scope. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/Scope.h" + +using namespace clang; + +void Scope::Init(Scope *parent, unsigned flags) { + AnyParent = parent; + Flags = flags; + + if (parent) { + Depth = parent->Depth + 1; + PrototypeDepth = parent->PrototypeDepth; + PrototypeIndex = 0; + FnParent = parent->FnParent; + BreakParent = parent->BreakParent; + ContinueParent = parent->ContinueParent; + ControlParent = parent->ControlParent; + BlockParent = parent->BlockParent; + TemplateParamParent = parent->TemplateParamParent; + } else { + Depth = 0; + PrototypeDepth = 0; + PrototypeIndex = 0; + FnParent = BreakParent = ContinueParent = BlockParent = 0; + ControlParent = 0; + TemplateParamParent = 0; + } + + // If this scope is a function or contains breaks/continues, remember it. + if (flags & FnScope) FnParent = this; + if (flags & BreakScope) BreakParent = this; + if (flags & ContinueScope) ContinueParent = this; + if (flags & ControlScope) ControlParent = this; + if (flags & BlockScope) BlockParent = this; + if (flags & TemplateParamScope) TemplateParamParent = this; + + // If this is a prototype scope, record that. + if (flags & FunctionPrototypeScope) PrototypeDepth++; + + DeclsInScope.clear(); + UsingDirectives.clear(); + Entity = 0; + ErrorTrap.reset(); +} diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index f589b2d4a951..7214988bdafc 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1247,11 +1247,15 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, // FunctionDecl. if (const FunctionProtoType *FT = dyn_cast(R)) { llvm::SmallVector Params; - for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) - Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), - SourceLocation(), 0, - FT->getArgType(i), /*TInfo=*/0, - SC_None, SC_None, 0)); + for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { + ParmVarDecl *parm = + ParmVarDecl::Create(Context, New, SourceLocation(), + SourceLocation(), 0, + FT->getArgType(i), /*TInfo=*/0, + SC_None, SC_None, 0); + parm->setScopeInfo(0, i); + Params.push_back(parm); + } New->setParams(Params.data(), Params.size()); } @@ -1780,6 +1784,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { *ParamType, /*TInfo=*/0, SC_None, SC_None, 0); + Param->setScopeInfo(0, Params.size()); Param->setImplicit(); Params.push_back(Param); } @@ -4431,6 +4436,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, AE = FT->arg_type_end(); AI != AE; ++AI) { ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, D.getIdentifierLoc(), *AI); + Param->setScopeInfo(0, Params.size()); Params.push_back(Param); } } else { @@ -5838,7 +5844,12 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { StorageClass, StorageClassAsWritten); if (D.isInvalidType()) - New->setInvalidDecl(); + New->setInvalidDecl(); + + assert(S->isFunctionPrototypeScope()); + assert(S->getFunctionPrototypeDepth() >= 1); + New->setScopeInfo(S->getFunctionPrototypeDepth() - 1, + S->getNextFunctionPrototypeIndex()); // Add the parameter declaration into this scope. S->AddDecl(New); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index dbe51a825239..92ba095cd6c8 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -757,6 +757,7 @@ namespace { QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL); ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, + int indexAdjustment, llvm::Optional NumExpansions); /// \brief Transforms a template type parameter type by performing @@ -1174,8 +1175,9 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, ParmVarDecl * TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm, + int indexAdjustment, llvm::Optional NumExpansions) { - return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, + return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment, NumExpansions); } @@ -1422,6 +1424,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, const MultiLevelTemplateArgumentList &TemplateArgs, + int indexAdjustment, llvm::Optional NumExpansions) { TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); TypeSourceInfo *NewDI = 0; @@ -1492,6 +1495,9 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, // FIXME: OldParm may come from a FunctionProtoType, in which case CurContext // can be anything, is this right ? NewParm->setDeclContext(CurContext); + + NewParm->setScopeInfo(OldParm->getFunctionScopeDepth(), + OldParm->getFunctionScopeIndex() + indexAdjustment); return NewParm; } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index e38ecd43b109..5412d1325a7e 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1468,7 +1468,8 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { } ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { - return SemaRef.SubstParmVarDecl(D, TemplateArgs, llvm::Optional()); + return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0, + llvm::Optional()); } Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 9f38f2aa3d56..2a71e14265a8 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -524,7 +524,11 @@ class TreeTransform { /// \brief Transforms a single function-type parameter. Return null /// on error. + /// + /// \param indexAdjustment - A number to add to the parameter's + /// scope index; can be negative ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, + int indexAdjustment, llvm::Optional NumExpansions); QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL); @@ -3682,6 +3686,7 @@ QualType TreeTransform::TransformExtVectorType(TypeLocBuilder &TLB, template ParmVarDecl * TreeTransform::TransformFunctionTypeParam(ParmVarDecl *OldParm, + int indexAdjustment, llvm::Optional NumExpansions) { TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); TypeSourceInfo *NewDI = 0; @@ -3716,19 +3721,22 @@ TreeTransform::TransformFunctionTypeParam(ParmVarDecl *OldParm, if (!NewDI) return 0; - if (NewDI == OldDI) + if (NewDI == OldDI && indexAdjustment == 0) return OldParm; - else - return ParmVarDecl::Create(SemaRef.Context, - OldParm->getDeclContext(), - OldParm->getInnerLocStart(), - OldParm->getLocation(), - OldParm->getIdentifier(), - NewDI->getType(), - NewDI, - OldParm->getStorageClass(), - OldParm->getStorageClassAsWritten(), - /* DefArg */ NULL); + + ParmVarDecl *newParm = ParmVarDecl::Create(SemaRef.Context, + OldParm->getDeclContext(), + OldParm->getInnerLocStart(), + OldParm->getLocation(), + OldParm->getIdentifier(), + NewDI->getType(), + NewDI, + OldParm->getStorageClass(), + OldParm->getStorageClassAsWritten(), + /* DefArg */ NULL); + newParm->setScopeInfo(OldParm->getFunctionScopeDepth(), + OldParm->getFunctionScopeIndex() + indexAdjustment); + return newParm; } template @@ -3738,8 +3746,12 @@ bool TreeTransform:: const QualType *ParamTypes, llvm::SmallVectorImpl &OutParamTypes, llvm::SmallVectorImpl *PVars) { + int indexAdjustment = 0; + for (unsigned i = 0; i != NumParams; ++i) { if (ParmVarDecl *OldParm = Params[i]) { + assert(OldParm->getFunctionScopeIndex() == i); + llvm::Optional NumExpansions; ParmVarDecl *NewParm = 0; if (OldParm->isParameterPack()) { @@ -3777,6 +3789,7 @@ bool TreeTransform:: Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); ParmVarDecl *NewParm = getDerived().TransformFunctionTypeParam(OldParm, + indexAdjustment++, OrigNumExpansions); if (!NewParm) return true; @@ -3792,6 +3805,7 @@ bool TreeTransform:: ForgetPartiallySubstitutedPackRAII Forget(getDerived()); ParmVarDecl *NewParm = getDerived().TransformFunctionTypeParam(OldParm, + indexAdjustment++, OrigNumExpansions); if (!NewParm) return true; @@ -3801,6 +3815,12 @@ bool TreeTransform:: PVars->push_back(NewParm); } + // The next parameter should have the same adjustment as the + // last thing we pushed, but we post-incremented indexAdjustment + // on every push. Also, if we push nothing, the adjustment should + // go down by one. + indexAdjustment--; + // We're done with the pack expansion. continue; } @@ -3809,9 +3829,11 @@ bool TreeTransform:: // expansion. Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); NewParm = getDerived().TransformFunctionTypeParam(OldParm, + indexAdjustment, NumExpansions); } else { NewParm = getDerived().TransformFunctionTypeParam(OldParm, + indexAdjustment, llvm::Optional()); } @@ -3902,8 +3924,16 @@ bool TreeTransform:: PVars->push_back(0); } - return false; +#ifndef NDEBUG + if (PVars) { + for (unsigned i = 0, e = PVars->size(); i != e; ++i) + if (ParmVarDecl *parm = (*PVars)[i]) + assert(parm->getFunctionScopeIndex() == i); } +#endif + + return false; +} template QualType diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 0645b278ac2b..665516470e9e 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -710,6 +710,8 @@ void ASTDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) { void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) { VisitVarDecl(PD); + unsigned scopeDepth = Record[Idx++], scopeIndex = Record[Idx++]; + PD->setScopeInfo(scopeDepth, scopeIndex); PD->ParmVarDeclBits.ObjCDeclQualifier = (Decl::ObjCDeclQualifier)Record[Idx++]; PD->ParmVarDeclBits.IsKNRPromoted = Record[Idx++]; PD->ParmVarDeclBits.HasInheritedDefaultArg = Record[Idx++]; diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 31eb003d0063..63cffb243a41 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -587,6 +587,8 @@ void ASTDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) { void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { VisitVarDecl(D); + Record.push_back(D->getFunctionScopeDepth()); + Record.push_back(D->getFunctionScopeIndex()); Record.push_back(D->getObjCDeclQualifier()); // FIXME: stable encoding Record.push_back(D->isKNRPromoted()); Record.push_back(D->hasInheritedDefaultArg()); @@ -1174,6 +1176,8 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // HasInit Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo // ParmVarDecl + Abv->Add(BitCodeAbbrevOp(0)); // ScopeDepth + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ScopeIndex Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier Abv->Add(BitCodeAbbrevOp(0)); // KNRPromoted Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedDefaultArg diff --git a/test/CodeGenCXX/mangle-exprs.cpp b/test/CodeGenCXX/mangle-exprs.cpp index 5014a9145e88..46c46f04a8a2 100644 --- a/test/CodeGenCXX/mangle-exprs.cpp +++ b/test/CodeGenCXX/mangle-exprs.cpp @@ -65,3 +65,47 @@ namespace test1 { b(s); } } + +namespace test2 { + template void a(T x, decltype(x()) y) {} + template auto b(T x) -> decltype(x()) { return x(); } + template void c(T x, void (*p)(decltype(x()))) {} + template void d(T x, auto (*p)() -> decltype(x())) {} + template void e(auto (*p)(T y) -> decltype(y())) {} + template void f(void (*p)(T x, decltype(x()) y)) {} + template void g(T x, decltype(x()) y) { + static decltype(x()) variable; + variable = 0; + } + template void h(T x, decltype((decltype(x())(*)()) 0) y) {} + template void i(decltype((auto (*)(T x) -> decltype(x())) 0) y) {} + + float foo(); + void bar(float); + float baz(float(*)()); + void fred(float(*)(), float); + + // CHECK: define void @_ZN5test211instantiateEv + void instantiate() { + // CHECK: call void @_ZN5test21aIPFfvEEEvT_DTclfL0p_EE( + a(foo, 0.0f); + // CHECK: call float @_ZN5test21bIPFfvEEEDTclfp_EET_( + (void) b(foo); + // CHECK: call void @_ZN5test21cIPFfvEEEvT_PFvDTclfL1p_EEE( + c(foo, bar); + // CHECK: call void @_ZN5test21dIPFfvEEEvT_PFDTclfL0p_EEvE( + d(foo, foo); + // CHECK: call void @_ZN5test21eIPFfvEEEvPFDTclfp_EET_E( + e(baz); + // CHECK: call void @_ZN5test21fIPFfvEEEvPFvT_DTclfL0p_EEE( + f(fred); + // CHECK: call void @_ZN5test21gIPFfvEEEvT_DTclfL0p_EE( + g(foo, 0.0f); + // CHECK: call void @_ZN5test21hIPFfvEEEvT_DTcvPFDTclfL0p_EEvELi0EE( + h(foo, foo); + // CHECK: call void @_ZN5test21iIPFfvEEEvDTcvPFDTclfp_EET_ELi0EE( + i(baz); + } + + // CHECK: store float {{.*}}, float* @_ZZN5test21gIPFfvEEEvT_DTclfL0p_EEE8variable, +}