From ed97649e9574b9d854fa4d6109c9333ae0993554 Mon Sep 17 00:00:00 2001 From: John McCall Date: Fri, 4 Dec 2009 22:46:56 +0000 Subject: [PATCH] Fix "using typename" and the instantiation of non-dependent using declarations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90614 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 27 ++- include/clang/AST/Type.h | 33 ++++ include/clang/AST/TypeLoc.h | 155 +++++++++++---- include/clang/AST/TypeLocBuilder.h | 45 +++-- include/clang/AST/TypeNodes.def | 1 + include/clang/Frontend/PCHBitCodes.h | 4 +- lib/AST/ASTContext.cpp | 41 ++-- lib/AST/TypeLoc.cpp | 29 +++ lib/AST/TypePrinter.cpp | 9 + lib/CodeGen/Mangle.cpp | 6 + lib/Frontend/PCHReader.cpp | 7 + lib/Frontend/PCHWriter.cpp | 11 ++ lib/Sema/Sema.h | 4 + lib/Sema/SemaDeclCXX.cpp | 83 +++++--- lib/Sema/SemaTemplateDeduction.cpp | 1 + lib/Sema/SemaTemplateInstantiate.cpp | 2 - lib/Sema/SemaTemplateInstantiateDecl.cpp | 84 +++++++- lib/Sema/TreeTransform.h | 51 +++++ .../basic.namespace/namespace.udecl/p4.cpp | 183 ++++++++++++++++++ test/SemaCXX/using-decl-templates.cpp | 11 ++ 20 files changed, 670 insertions(+), 117 deletions(-) create mode 100644 test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 6efb634a8c..78ead42007 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -57,6 +57,7 @@ namespace clang { class TypeDecl; class TypedefDecl; class UsingDecl; + class UsingShadowDecl; namespace Builtin { class Context; } @@ -183,8 +184,10 @@ class ASTContext { llvm::DenseMap InstantiatedFromStaticDataMember; - /// \brief Keeps track of the UnresolvedUsingDecls from which UsingDecls - /// where created during instantiation. + /// \brief Keeps track of the declaration from which a UsingDecl was + /// created during instantiation. The source declaration is always + /// a UsingDecl, an UnresolvedUsingValueDecl, or an + /// UnresolvedUsingTypenameDecl. /// /// For example: /// \code @@ -203,8 +206,10 @@ class ASTContext { /// /// This mapping will contain an entry that maps from the UsingDecl in /// B to the UnresolvedUsingDecl in B. - llvm::DenseMap - InstantiatedFromUnresolvedUsingDecl; + llvm::DenseMap InstantiatedFromUsingDecl; + + llvm::DenseMap + InstantiatedFromUsingShadowDecl; llvm::DenseMap InstantiatedFromUnnamedFieldDecl; @@ -282,14 +287,18 @@ public: void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, TemplateSpecializationKind TSK); - /// \brief If this using decl is instantiated from an unresolved using decl, + /// \brief If the given using decl is an instantiation of a + /// (possibly unresolved) using decl from a template instantiation, /// return it. - NamedDecl *getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD); + NamedDecl *getInstantiatedFromUsingDecl(UsingDecl *Inst); - /// \brief Note that the using decl \p Inst is an instantiation of - /// the unresolved using decl \p Tmpl of a class template. - void setInstantiatedFromUnresolvedUsingDecl(UsingDecl *Inst, NamedDecl *Tmpl); + /// \brief Remember that the using decl \p Inst is an instantiation + /// of the using decl \p Pattern of a class template. + void setInstantiatedFromUsingDecl(UsingDecl *Inst, NamedDecl *Pattern); + void setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst, + UsingShadowDecl *Pattern); + UsingShadowDecl *getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst); FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field); diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 16b6dd7215..7b5598c460 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -76,6 +76,7 @@ namespace clang { class ObjCInterfaceDecl; class ObjCProtocolDecl; class ObjCMethodDecl; + class UnresolvedUsingTypenameDecl; class Expr; class Stmt; class SourceLocation; @@ -1863,6 +1864,38 @@ public: }; +/// \brief Represents the dependent type named by a dependently-scoped +/// typename using declaration, e.g. +/// using typename Base::foo; +/// Template instantiation turns these into the underlying type. +class UnresolvedUsingType : public Type { + UnresolvedUsingTypenameDecl *Decl; + + UnresolvedUsingType(UnresolvedUsingTypenameDecl *D) + : Type(UnresolvedUsing, QualType(), true), Decl(D) {} + friend class ASTContext; // ASTContext creates these. +public: + + UnresolvedUsingTypenameDecl *getDecl() const { return Decl; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == UnresolvedUsing; + } + static bool classof(const UnresolvedUsingType *) { return true; } + + void Profile(llvm::FoldingSetNodeID &ID) { + return Profile(ID, Decl); + } + static void Profile(llvm::FoldingSetNodeID &ID, + UnresolvedUsingTypenameDecl *D) { + ID.AddPointer(D); + } +}; + + class TypedefType : public Type { TypedefDecl *Decl; protected: diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index f08ca6bf46..47274450b1 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -340,16 +340,20 @@ public: } }; + struct TypeSpecLocInfo { SourceLocation NameLoc; }; /// \brief A reasonable base class for TypeLocs that correspond to /// types that are written as a type-specifier. -template -class TypeSpecTypeLoc - : public ConcreteTypeLoc { +class TypeSpecTypeLoc : public ConcreteTypeLoc { public: + enum { LocalDataSize = sizeof(TypeSpecLocInfo) }; + SourceLocation getNameLoc() const { return this->getLocalData()->NameLoc; } @@ -362,31 +366,79 @@ public: void initializeLocal(SourceLocation Loc) { setNameLoc(Loc); } + + static bool classof(const TypeLoc *TL); + static bool classof(const TypeSpecTypeLoc *TL) { return true; } }; + /// \brief Wrapper for source info for typedefs. -class TypedefTypeLoc : public TypeSpecTypeLoc { +class TypedefTypeLoc : public InheritingConcreteTypeLoc { public: TypedefDecl *getTypedefDecl() const { return getTypePtr()->getDecl(); } }; +/// \brief Wrapper for source info for unresolved typename using decls. +class UnresolvedUsingTypeLoc : + public InheritingConcreteTypeLoc { +public: + UnresolvedUsingTypenameDecl *getDecl() const { + return getTypePtr()->getDecl(); + } +}; + +/// \brief Wrapper for source info for tag types. Note that this only +/// records source info for the name itself; a type written 'struct foo' +/// should be represented as an ElaboratedTypeLoc. We currently +/// only do that when C++ is enabled because of the expense of +/// creating an ElaboratedType node for so many type references in C. +class TagTypeLoc : public InheritingConcreteTypeLoc { +public: + TagDecl *getDecl() const { return getTypePtr()->getDecl(); } +}; + +/// \brief Wrapper for source info for record types. +class RecordTypeLoc : public InheritingConcreteTypeLoc { +public: + RecordDecl *getDecl() const { return getTypePtr()->getDecl(); } +}; + +/// \brief Wrapper for source info for enum types. +class EnumTypeLoc : public InheritingConcreteTypeLoc { +public: + EnumDecl *getDecl() const { return getTypePtr()->getDecl(); } +}; /// \brief Wrapper for source info for builtin types. -class BuiltinTypeLoc : public TypeSpecTypeLoc { +class BuiltinTypeLoc : public InheritingConcreteTypeLoc { }; /// \brief Wrapper for template type parameters. -class TemplateTypeParmTypeLoc : public TypeSpecTypeLoc { +class TemplateTypeParmTypeLoc : + public InheritingConcreteTypeLoc { }; /// \brief Wrapper for substituted template type parameters. class SubstTemplateTypeParmTypeLoc : - public TypeSpecTypeLoc { + public InheritingConcreteTypeLoc { }; @@ -944,63 +996,84 @@ private: } }; -// None of these types have proper implementations yet. +//===----------------------------------------------------------------------===// +// +// All of these need proper implementations. +// +//===----------------------------------------------------------------------===// -class VectorTypeLoc : public TypeSpecTypeLoc { +// FIXME: size expression and attribute locations (or keyword if we +// ever fully support altivec syntax). +class VectorTypeLoc : public InheritingConcreteTypeLoc { }; +// FIXME: size expression and attribute locations. class ExtVectorTypeLoc : public InheritingConcreteTypeLoc { }; +// FIXME: attribute locations. // For some reason, this isn't a subtype of VectorType. class DependentSizedExtVectorTypeLoc : - public TypeSpecTypeLoc { + public InheritingConcreteTypeLoc { }; -class FixedWidthIntTypeLoc : public TypeSpecTypeLoc { +// FIXME: I'm not sure how you actually specify these; with attributes? +class FixedWidthIntTypeLoc : + public InheritingConcreteTypeLoc { }; -class ComplexTypeLoc : public TypeSpecTypeLoc { +// FIXME: location of the '_Complex' keyword. +class ComplexTypeLoc : public InheritingConcreteTypeLoc { }; -class TypeOfExprTypeLoc : public TypeSpecTypeLoc { +// FIXME: location of the 'typeof' and parens (the expression is +// carried by the type). +class TypeOfExprTypeLoc : public InheritingConcreteTypeLoc { }; -class TypeOfTypeLoc : public TypeSpecTypeLoc { +// FIXME: location of the 'typeof' and parens; also the DeclaratorInfo +// for the inner type, or (maybe) just express that inline to the TypeLoc. +class TypeOfTypeLoc : public InheritingConcreteTypeLoc { }; -class DecltypeTypeLoc : public TypeSpecTypeLoc { -}; - -class TagTypeLoc : public TypeSpecTypeLoc { -}; - -class RecordTypeLoc : public InheritingConcreteTypeLoc { -}; - -class EnumTypeLoc : public InheritingConcreteTypeLoc { +// FIXME: location of the 'decltype' and parens. +class DecltypeTypeLoc : public InheritingConcreteTypeLoc { }; -class ElaboratedTypeLoc : public TypeSpecTypeLoc { +// FIXME: location of the tag keyword. +class ElaboratedTypeLoc : public InheritingConcreteTypeLoc { }; -class QualifiedNameTypeLoc : public TypeSpecTypeLoc { +// FIXME: locations for the nested name specifier; at the very least, +// a SourceRange. +class QualifiedNameTypeLoc : + public InheritingConcreteTypeLoc { }; -class TypenameTypeLoc : public TypeSpecTypeLoc { +// FIXME: locations for the typename keyword and nested name specifier. +class TypenameTypeLoc : public InheritingConcreteTypeLoc { }; } diff --git a/include/clang/AST/TypeLocBuilder.h b/include/clang/AST/TypeLocBuilder.h index 00e2b7f832..f4263c3de3 100644 --- a/include/clang/AST/TypeLocBuilder.h +++ b/include/clang/AST/TypeLocBuilder.h @@ -59,9 +59,35 @@ class TypeLocBuilder { grow(Requested); } - /// Pushes space for a new TypeLoc onto the given type. Invalidates + /// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs + /// previously retrieved from this builder. + TypeSpecTypeLoc pushTypeSpec(QualType T) { + size_t LocalSize = TypeSpecTypeLoc::LocalDataSize; + return cast(pushImpl(T, LocalSize)); + } + + + /// Pushes space for a new TypeLoc of the given type. Invalidates /// any TypeLocs previously retrieved from this builder. template TyLocType push(QualType T) { + size_t LocalSize = cast(TypeLoc(T, 0)).getLocalDataSize(); + return cast(pushImpl(T, LocalSize)); + } + + /// Creates a DeclaratorInfo for the given type. + DeclaratorInfo *getDeclaratorInfo(ASTContext& Context, QualType T) { +#ifndef NDEBUG + assert(T == LastTy && "type doesn't match last type pushed!"); +#endif + + size_t FullDataSize = Capacity - Index; + DeclaratorInfo *DI = Context.CreateDeclaratorInfo(T, FullDataSize); + memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize); + return DI; + } + +private: + TypeLoc pushImpl(QualType T, size_t LocalSize) { #ifndef NDEBUG QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType(); assert(TLast == LastTy && @@ -69,8 +95,6 @@ class TypeLocBuilder { LastTy = T; #endif - size_t LocalSize = cast(TypeLoc(T, 0)).getLocalDataSize(); - // If we need to grow, grow by a factor of 2. if (LocalSize > Index) { size_t RequiredCapacity = Capacity + (LocalSize - Index); @@ -82,22 +106,9 @@ class TypeLocBuilder { Index -= LocalSize; - return cast(TypeLoc(T, &Buffer[Index])); - } - - /// Creates a DeclaratorInfo for the given type. - DeclaratorInfo *getDeclaratorInfo(ASTContext& Context, QualType T) { -#ifndef NDEBUG - assert(T == LastTy && "type doesn't match last type pushed!"); -#endif - - size_t FullDataSize = Capacity - Index; - DeclaratorInfo *DI = Context.CreateDeclaratorInfo(T, FullDataSize); - memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize); - return DI; + return TypeLoc(T, &Buffer[Index]); } - private: /// Grow to the given capacity. void grow(size_t NewCapacity) { assert(NewCapacity > Capacity); diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index c2721236af..b9d37992a6 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -71,6 +71,7 @@ TYPE(ExtVector, VectorType) ABSTRACT_TYPE(Function, Type) TYPE(FunctionProto, FunctionType) TYPE(FunctionNoProto, FunctionType) +DEPENDENT_TYPE(UnresolvedUsing, Type) NON_CANONICAL_TYPE(Typedef, Type) NON_CANONICAL_TYPE(TypeOfExpr, Type) NON_CANONICAL_TYPE(TypeOf, Type) diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 98463c308e..c8c49c83f9 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -404,7 +404,9 @@ namespace clang { /// \brief An ElaboratedType record. TYPE_ELABORATED = 24, /// \brief A SubstTemplateTypeParmType record. - TYPE_SUBST_TEMPLATE_TYPE_PARM = 25 + TYPE_SUBST_TEMPLATE_TYPE_PARM = 25, + /// \brief An UnresolvedUsingType record. + TYPE_UNRESOLVED_USING = 26 }; /// \brief The type IDs for special types constructed by semantic diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index a63db14a0f..94f2fdcff9 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -260,24 +260,40 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, } NamedDecl * -ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) { +ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) { llvm::DenseMap::const_iterator Pos - = InstantiatedFromUnresolvedUsingDecl.find(UUD); - if (Pos == InstantiatedFromUnresolvedUsingDecl.end()) + = InstantiatedFromUsingDecl.find(UUD); + if (Pos == InstantiatedFromUsingDecl.end()) return 0; return Pos->second; } void -ASTContext::setInstantiatedFromUnresolvedUsingDecl(UsingDecl *UD, - NamedDecl *UUD) { - assert((isa(UUD) || - isa(UUD)) && - "original declaration is not an unresolved using decl"); - assert(!InstantiatedFromUnresolvedUsingDecl[UD] && - "Already noted what using decl what instantiated from"); - InstantiatedFromUnresolvedUsingDecl[UD] = UUD; +ASTContext::setInstantiatedFromUsingDecl(UsingDecl *Inst, NamedDecl *Pattern) { + assert((isa(Pattern) || + isa(Pattern) || + isa(Pattern)) && + "pattern decl is not a using decl"); + assert(!InstantiatedFromUsingDecl[Inst] && "pattern already exists"); + InstantiatedFromUsingDecl[Inst] = Pattern; +} + +UsingShadowDecl * +ASTContext::getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst) { + llvm::DenseMap::const_iterator Pos + = InstantiatedFromUsingShadowDecl.find(Inst); + if (Pos == InstantiatedFromUsingShadowDecl.end()) + return 0; + + return Pos->second; +} + +void +ASTContext::setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst, + UsingShadowDecl *Pattern) { + assert(!InstantiatedFromUsingShadowDecl[Inst] && "pattern already exists"); + InstantiatedFromUsingShadowDecl[Inst] = Pattern; } FieldDecl *ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) { @@ -1766,6 +1782,9 @@ QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) { Decl->TypeForDecl = PrevDecl->TypeForDecl; else Decl->TypeForDecl = new (*this, TypeAlignment) EnumType(Enum); + } else if (UnresolvedUsingTypenameDecl *Using = + dyn_cast(Decl)) { + Decl->TypeForDecl = new (*this, TypeAlignment) UnresolvedUsingType(Using); } else assert(false && "TypeDecl without a type?"); diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 50a512028e..3ccb7a9cc6 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -94,3 +94,32 @@ void TypeLoc::initializeImpl(TypeLoc TL, SourceLocation Loc) { TypeLocInitializer(Loc).Visit(TL); } while ((TL = TL.getNextTypeLoc())); } + +namespace { + struct TSTChecker : public TypeLocVisitor { + // Overload resolution does the real work for us. + static bool isTypeSpec(TypeSpecTypeLoc _) { return true; } + static bool isTypeSpec(TypeLoc _) { return false; } + +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return isTypeSpec(TyLoc); \ + } +#include "clang/AST/TypeLocNodes.def" + }; +} + + +/// \brief Determines if the given type loc corresponds to a +/// TypeSpecTypeLoc. Since there is not actually a TypeSpecType in +/// the type hierarchy, this is made somewhat complicated. +/// +/// There are a lot of types that currently use TypeSpecTypeLoc +/// because it's a convenient base class. Ideally we would not accept +/// those here, but ideally we would have better implementations for +/// them. +bool TypeSpecTypeLoc::classof(const TypeLoc *TL) { + if (TL->getType().hasLocalQualifiers()) return false; + return TSTChecker().Visit(*TL); +} diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 3d7a5376d7..2f58ebed4b 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -303,6 +303,15 @@ void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T, Print(T->getResultType(), S); } +void TypePrinter::PrintUnresolvedUsing(const UnresolvedUsingType *T, + std::string &S) { + IdentifierInfo *II = T->getDecl()->getIdentifier(); + if (S.empty()) + S = II->getName().str(); + else + S = II->getName().str() + ' ' + S; +} + void TypePrinter::PrintTypedef(const TypedefType *T, std::string &S) { if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'. S = ' ' + S; diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 4d021e8964..df708eda9c 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -841,6 +841,12 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, Out << 'z'; } +// ::= +// ::= +void CXXNameMangler::mangleType(const UnresolvedUsingType *T) { + mangleName(T->getDecl()); +} + // ::= // ::= void CXXNameMangler::mangleType(const EnumType *T) { diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 40eb9ca536..811f9ed4af 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -1880,6 +1880,10 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { Exceptions.data()); } + case pch::TYPE_UNRESOLVED_USING: + return Context->getTypeDeclType( + cast(GetDecl(Record[0]))); + case pch::TYPE_TYPEDEF: assert(Record.size() == 1 && "incorrect encoding of typedef type"); return Context->getTypeDeclType(cast(GetDecl(Record[0]))); @@ -2044,6 +2048,9 @@ void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } +void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index e79f9c9dac..0e6d1d2f66 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -166,6 +166,14 @@ void PCHTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { Code = pch::TYPE_FUNCTION_PROTO; } +#if 0 +// For when we want it.... +void PCHTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + Code = pch::TYPE_UNRESOLVED_USING; +} +#endif + void PCHTypeWriter::VisitTypedefType(const TypedefType *T) { Writer.AddDeclRef(T->getDecl(), Record); Code = pch::TYPE_TYPEDEF; @@ -337,6 +345,9 @@ void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } +void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 616151efea..9606821f78 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1729,6 +1729,10 @@ public: SourceLocation IdentLoc, IdentifierInfo *Ident); + bool CheckUsingDeclQualifier(SourceLocation UsingLoc, + const CXXScopeSpec &SS, + SourceLocation NameLoc); + NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, const CXXScopeSpec &SS, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 58b5633afa..992bb80189 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2900,10 +2900,8 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, TargetName, AttrList, /* IsInstantiation */ false, IsTypeName, TypenameLoc); - if (UD) { - PushOnScopeChains(UD, S); - UD->setAccess(AS); - } + if (UD) + PushOnScopeChains(UD, S, /*AddToContext*/ false); return DeclPtrTy::make(UD); } @@ -2962,19 +2960,33 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, NestedNameSpecifier *NNS = static_cast(SS.getScopeRep()); + if (CheckUsingDeclQualifier(UsingLoc, SS, IdentLoc)) + return 0; + DeclContext *LookupContext = computeDeclContext(SS); + NamedDecl *D; if (!LookupContext) { if (IsTypeName) { - return UnresolvedUsingTypenameDecl::Create(Context, CurContext, - UsingLoc, TypenameLoc, - SS.getRange(), NNS, - IdentLoc, Name); - } else { - return UnresolvedUsingValueDecl::Create(Context, CurContext, - UsingLoc, SS.getRange(), NNS, + // FIXME: not all declaration name kinds are legal here + D = UnresolvedUsingTypenameDecl::Create(Context, CurContext, + UsingLoc, TypenameLoc, + SS.getRange(), NNS, IdentLoc, Name); + } else { + D = UnresolvedUsingValueDecl::Create(Context, CurContext, + UsingLoc, SS.getRange(), NNS, + IdentLoc, Name); } + } else { + D = UsingDecl::Create(Context, CurContext, IdentLoc, + SS.getRange(), UsingLoc, NNS, Name, + IsTypeName); } + D->setAccess(AS); + CurContext->addDecl(D); + + if (!LookupContext) return D; + UsingDecl *UD = cast(D); if (const CXXRecordDecl *RD = dyn_cast(CurContext)) { // C++0x N2914 [namespace.udecl]p3: @@ -2989,7 +3001,8 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, Diag(SS.getRange().getBegin(), diag::err_using_decl_nested_name_specifier_is_not_a_base_class) << NNS << RD->getDeclName(); - return 0; + UD->setInvalidDecl(); + return UD; } } else { // C++0x N2914 [namespace.udecl]p8: @@ -2997,7 +3010,8 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, if (isa(LookupContext)) { Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_class_member) << SS.getRange(); - return 0; + UD->setInvalidDecl(); + return UD; } } @@ -3017,54 +3031,63 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, if (R.empty()) { Diag(IdentLoc, diag::err_no_member) << Name << LookupContext << SS.getRange(); - return 0; + UD->setInvalidDecl(); + return UD; } - if (R.isAmbiguous()) - return 0; + if (R.isAmbiguous()) { + UD->setInvalidDecl(); + return UD; + } if (IsTypeName) { // If we asked for a typename and got a non-type decl, error out. - if (R.getResultKind() != LookupResult::Found - || !isa(R.getFoundDecl())) { + if (!R.getAsSingle()) { Diag(IdentLoc, diag::err_using_typename_non_type); for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) Diag((*I)->getUnderlyingDecl()->getLocation(), diag::note_using_decl_target); - return 0; + UD->setInvalidDecl(); + return UD; } } else { // If we asked for a non-typename and we got a type, error out, // but only if this is an instantiation of an unresolved using // decl. Otherwise just silently find the type name. - if (IsInstantiation && - R.getResultKind() == LookupResult::Found && - isa(R.getFoundDecl())) { + if (IsInstantiation && R.getAsSingle()) { Diag(IdentLoc, diag::err_using_dependent_value_is_type); Diag(R.getFoundDecl()->getLocation(), diag::note_using_decl_target); - return 0; + UD->setInvalidDecl(); + return UD; } } // C++0x N2914 [namespace.udecl]p6: // A using-declaration shall not name a namespace. - if (R.getResultKind() == LookupResult::Found - && isa(R.getFoundDecl())) { + if (R.getAsSingle()) { Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace) << SS.getRange(); - return 0; + UD->setInvalidDecl(); + return UD; } - UsingDecl *UD = UsingDecl::Create(Context, CurContext, IdentLoc, - SS.getRange(), UsingLoc, NNS, Name, - IsTypeName); - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) BuildUsingShadowDecl(*this, S, AS, UD, *I); return UD; } +/// Checks that the given nested-name qualifier used in a using decl +/// in the current context is appropriately related to the current +/// scope. If an error is found, diagnoses it and returns true. +bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, + const CXXScopeSpec &SS, + SourceLocation NameLoc) { + // FIXME: implement + + return false; +} + Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, SourceLocation AliasLoc, diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 613ffde573..b4754db7d6 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -2361,6 +2361,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, case Type::Enum: case Type::ObjCInterface: case Type::ObjCObjectPointer: + case Type::UnresolvedUsing: #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 122e85eaa5..6a4ac3c562 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1064,8 +1064,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Invalid = true; } else if (FieldDecl *Field = dyn_cast(NewMember)) Fields.push_back(DeclPtrTy::make(Field)); - else if (UsingDecl *UD = dyn_cast(NewMember)) - Instantiation->addDecl(UD); } else { // FIXME: Eventually, a NULL return will mean that one of the // instantiations was a semantic disaster, and we'll want to set Invalid = diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index ec28f47417..6b41d9a9b2 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -66,6 +66,8 @@ namespace { Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + Decl *VisitUsingDecl(UsingDecl *D); + Decl *VisitUsingShadowDecl(UsingShadowDecl *D); Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); @@ -1034,6 +1036,56 @@ Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { return Inst; } +Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { + // The nested name specifier is non-dependent, so no transformation + // is required. + + UsingDecl *NewUD = UsingDecl::Create(SemaRef.Context, Owner, + D->getLocation(), + D->getNestedNameRange(), + D->getUsingLocation(), + D->getTargetNestedNameDecl(), + D->getDeclName(), + D->isTypeName()); + + CXXScopeSpec SS; + SS.setScopeRep(D->getTargetNestedNameDecl()); + SS.setRange(D->getNestedNameRange()); + if (SemaRef.CheckUsingDeclQualifier(D->getUsingLocation(), SS, + D->getLocation())) + NewUD->setInvalidDecl(); + SemaRef.Context.setInstantiatedFromUsingDecl(NewUD, D); + NewUD->setAccess(D->getAccess()); + Owner->addDecl(NewUD); + + // We'll transform the UsingShadowDecls as we reach them. + + return NewUD; +} + +Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) { + UsingDecl *InstUsing = + cast(SemaRef.FindInstantiatedDecl(D->getUsingDecl(), + TemplateArgs)); + NamedDecl *InstTarget = + cast(SemaRef.FindInstantiatedDecl(D->getTargetDecl(), + TemplateArgs)); + + UsingShadowDecl *InstD = UsingShadowDecl::Create(SemaRef.Context, Owner, + InstUsing->getLocation(), + InstUsing, InstTarget); + InstUsing->addShadowDecl(InstD); + + if (InstTarget->isInvalidDecl() || InstUsing->isInvalidDecl()) + InstD->setInvalidDecl(); + + SemaRef.Context.setInstantiatedFromUsingShadowDecl(InstD, D); + InstD->setAccess(D->getAccess()); + Owner->addDecl(InstD); + + return InstD; +} + Decl * TemplateDeclInstantiator ::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { NestedNameSpecifier *NNS = @@ -1054,8 +1106,8 @@ Decl * TemplateDeclInstantiator /*instantiation*/ true, /*typename*/ true, D->getTypenameLoc()); if (UD) - SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast(UD), - D); + SemaRef.Context.setInstantiatedFromUsingDecl(cast(UD), D); + return UD; } @@ -1079,8 +1131,8 @@ Decl * TemplateDeclInstantiator /*instantiation*/ true, /*typename*/ false, SourceLocation()); if (UD) - SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast(UD), - D); + SemaRef.Context.setInstantiatedFromUsingDecl(cast(UD), D); + return UD; } @@ -1753,16 +1805,28 @@ static bool isInstantiationOf(EnumDecl *Pattern, return false; } +static bool isInstantiationOf(UsingShadowDecl *Pattern, + UsingShadowDecl *Instance, + ASTContext &C) { + return C.getInstantiatedFromUsingShadowDecl(Instance) == Pattern; +} + +static bool isInstantiationOf(UsingDecl *Pattern, + UsingDecl *Instance, + ASTContext &C) { + return C.getInstantiatedFromUsingDecl(Instance) == Pattern; +} + static bool isInstantiationOf(UnresolvedUsingValueDecl *Pattern, UsingDecl *Instance, ASTContext &C) { - return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern; + return C.getInstantiatedFromUsingDecl(Instance) == Pattern; } static bool isInstantiationOf(UnresolvedUsingTypenameDecl *Pattern, UsingDecl *Instance, ASTContext &C) { - return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern; + return C.getInstantiatedFromUsingDecl(Instance) == Pattern; } static bool isInstantiationOfStaticDataMember(VarDecl *Pattern, @@ -1780,6 +1844,8 @@ static bool isInstantiationOfStaticDataMember(VarDecl *Pattern, return false; } +// Other is the prospective instantiation +// D is the prospective pattern static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { if (D->getKind() != Other->getKind()) { if (UnresolvedUsingTypenameDecl *UUD @@ -1831,6 +1897,12 @@ static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { } } + if (UsingDecl *Using = dyn_cast(Other)) + return isInstantiationOf(cast(D), Using, Ctx); + + if (UsingShadowDecl *Shadow = dyn_cast(Other)) + return isInstantiationOf(cast(D), Shadow, Ctx); + return D->getDeclName() && isa(Other) && D->getDeclName() == cast(Other)->getDeclName(); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index e1ac3225d2..b029a37967 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -461,6 +461,10 @@ public: /// \brief Build a new unprototyped function type. QualType RebuildFunctionNoProtoType(QualType ResultType); + /// \brief Rebuild an unresolved typename type, given the decl that + /// the UnresolvedUsingTypenameDecl was transformed to. + QualType RebuildUnresolvedUsingType(Decl *D); + /// \brief Build a new typedef type. QualType RebuildTypedefType(TypedefDecl *Typedef) { return SemaRef.Context.getTypeDeclType(Typedef); @@ -2578,6 +2582,29 @@ QualType TreeTransform::TransformFunctionNoProtoType( return Result; } +template QualType +TreeTransform::TransformUnresolvedUsingType(TypeLocBuilder &TLB, + UnresolvedUsingTypeLoc TL) { + UnresolvedUsingType *T = TL.getTypePtr(); + Decl *D = getDerived().TransformDecl(T->getDecl()); + if (!D) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || D != T->getDecl()) { + Result = getDerived().RebuildUnresolvedUsingType(D); + if (Result.isNull()) + return QualType(); + } + + // We might get an arbitrary type spec type back. We should at + // least always get a type spec type, though. + TypeSpecTypeLoc NewTL = TLB.pushTypeSpec(Result); + NewTL.setNameLoc(TL.getNameLoc()); + + return Result; +} + template QualType TreeTransform::TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { @@ -5317,6 +5344,30 @@ QualType TreeTransform::RebuildFunctionNoProtoType(QualType T) { return SemaRef.Context.getFunctionNoProtoType(T); } +template +QualType TreeTransform::RebuildUnresolvedUsingType(Decl *D) { + assert(D && "no decl found"); + if (D->isInvalidDecl()) return QualType(); + + TypeDecl *Ty; + if (isa(D)) { + UsingDecl *Using = cast(D); + assert(Using->isTypeName() && + "UnresolvedUsingTypenameDecl transformed to non-typename using"); + + // A valid resolved using typename decl points to exactly one type decl. + assert(++Using->shadow_begin() == Using->shadow_end()); + Ty = cast((*Using->shadow_begin())->getTargetDecl()); + + } else { + assert(isa(D) && + "UnresolvedUsingTypenameDecl transformed to non-using decl"); + Ty = cast(D); + } + + return SemaRef.Context.getTypeDeclType(Ty); +} + template QualType TreeTransform::RebuildTypeOfExprType(ExprArg E) { return SemaRef.BuildTypeofExprType(E.takeAs()); diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp new file mode 100644 index 0000000000..deed96b4a9 --- /dev/null +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp @@ -0,0 +1,183 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// C++03 [namespace.udecl]p4: +// A using-declaration used as a member-declaration shall refer to a +// member of a base class of the class being defined, shall refer to +// a member of an anonymous union that is a member of a base class +// of the class being defined, or shall refer to an enumerator for +// an enumeration type that is a member of a base class of the class +// being defined. + +// There is no directly analogous paragraph in C++0x, and the feature +// works sufficiently differently there that it needs a separate test. + +namespace test0 { + namespace NonClass { + typedef int type; + struct hiding {}; + int hiding; + static union { double union_member; }; + enum tagname { enumerator }; + } + + class Test0 { + using NonClass::type; // expected-error {{not a base class}} + using NonClass::hiding; // expected-error {{not a base class}} + using NonClass::union_member; // expected-error {{not a base class}} + using NonClass::enumerator; // expected-error {{not a base class}} + }; +} + +struct Opaque0 {}; + +namespace test1 { + struct A { + typedef int type; + struct hiding {}; // expected-note {{previous use is here}} + Opaque0 hiding; + union { double union_member; }; + enum tagname { enumerator }; + }; + + struct B : A { + using A::type; + using A::hiding; + using A::union_member; + using A::enumerator; + using A::tagname; + + void test0() { + type t = 0; + } + + void test1() { + typedef struct A::hiding local; + struct hiding _ = local(); + } + + void test2() { + union hiding _; // expected-error {{tag type that does not match previous}} + } + + void test3() { + char array[sizeof(union_member) == sizeof(double) ? 1 : -1]; + } + + void test4() { + enum tagname _ = enumerator; + } + + void test5() { + Opaque0 _ = hiding; + } + }; +} + +namespace test2 { + struct A { + typedef int type; + struct hiding {}; // expected-note {{previous use is here}} + int hiding; + union { double union_member; }; + enum tagname { enumerator }; + }; + + template struct B : A { + using A::type; + using A::hiding; + using A::union_member; + using A::enumerator; + using A::tagname; + + void test0() { + type t = 0; + } + + void test1() { + typedef struct A::hiding local; + struct hiding _ = local(); + } + + void test2() { + union hiding _; // expected-error {{tag type that does not match previous}} + } + + void test3() { + char array[sizeof(union_member) == sizeof(double) ? 1 : -1]; + } + + void test4() { + enum tagname _ = enumerator; + } + + void test5() { + Opaque0 _ = hiding; + } + }; +} + +namespace test3 { + struct hiding {}; + + template struct A { + typedef int type; // expected-note {{target of using declaration}} + struct hiding {}; + Opaque0 hiding; // expected-note {{target of using declaration}} + union { double union_member; }; // expected-note {{target of using declaration}} + enum tagname { enumerator }; // expected-note 2 {{target of using declaration}} + }; + + template struct B : A { + using A::type; // expected-error {{dependent using declaration resolved to type without 'typename'}} + using A::hiding; + using A::union_member; + using A::enumerator; + using A::tagname; // expected-error {{dependent using declaration resolved to type without 'typename'}} + + // FIXME: re-enable these when the various bugs involving tags are fixed +#if 0 + void test1() { + typedef struct A::hiding local; + struct hiding _ = local(); + } + + void test2() { + typedef struct A::hiding local; + union hiding _ = local(); + } +#endif + + void test3() { + char array[sizeof(union_member) == sizeof(double) ? 1 : -1]; + } + +#if 0 + void test4() { + enum tagname _ = enumerator; + } +#endif + + void test5() { + Opaque0 _ = hiding; + } + }; + + template struct B; // expected-note {{in instantiation}} + + template struct C : A { + using typename A::type; + using typename A::hiding; // expected-error {{'typename' keyword used on a non-type}} + using typename A::union_member; // expected-error {{'typename' keyword used on a non-type}} + using typename A::enumerator; // expected-error {{'typename' keyword used on a non-type}} + + void test6() { + type t = 0; + } + + void test7() { + Opaque0 _ = hiding; // expected-error {{expected '(' for function-style cast or type construction}} + } + }; + + template struct C; // expected-note {{in instantiation}} +} diff --git a/test/SemaCXX/using-decl-templates.cpp b/test/SemaCXX/using-decl-templates.cpp index 684009b78a..63fa4610cb 100644 --- a/test/SemaCXX/using-decl-templates.cpp +++ b/test/SemaCXX/using-decl-templates.cpp @@ -34,3 +34,14 @@ template struct E : A { void g() { f(); } }; + +namespace test0 { + struct Base { + int foo; + }; + template struct E : Base { + using Base::foo; + }; + + template struct E; +} -- 2.40.0