Fix "using typename" and the instantiation of non-dependent using declarations.
llvm-svn: 90614
This commit is contained in:
parent
9e2792690b
commit
b96ec56871
|
@ -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<const VarDecl *, MemberSpecializationInfo *>
|
||||
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<int> to the UnresolvedUsingDecl in B<T>.
|
||||
llvm::DenseMap<UsingDecl *, NamedDecl *>
|
||||
InstantiatedFromUnresolvedUsingDecl;
|
||||
llvm::DenseMap<UsingDecl *, NamedDecl *> InstantiatedFromUsingDecl;
|
||||
|
||||
llvm::DenseMap<UsingShadowDecl*, UsingShadowDecl*>
|
||||
InstantiatedFromUsingShadowDecl;
|
||||
|
||||
llvm::DenseMap<FieldDecl *, FieldDecl *> 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);
|
||||
|
||||
|
|
|
@ -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<T>::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:
|
||||
|
|
|
@ -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 Derived, class TypeClass, class LocalData = TypeSpecLocInfo>
|
||||
class TypeSpecTypeLoc
|
||||
: public ConcreteTypeLoc<UnqualTypeLoc, Derived, TypeClass, LocalData> {
|
||||
class TypeSpecTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
TypeSpecTypeLoc,
|
||||
Type,
|
||||
TypeSpecLocInfo> {
|
||||
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<TypedefTypeLoc,TypedefType> {
|
||||
class TypedefTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
TypedefTypeLoc,
|
||||
TypedefType> {
|
||||
public:
|
||||
TypedefDecl *getTypedefDecl() const {
|
||||
return getTypePtr()->getDecl();
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for unresolved typename using decls.
|
||||
class UnresolvedUsingTypeLoc :
|
||||
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
UnresolvedUsingTypeLoc,
|
||||
UnresolvedUsingType> {
|
||||
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<TypeSpecTypeLoc,
|
||||
TagTypeLoc,
|
||||
TagType> {
|
||||
public:
|
||||
TagDecl *getDecl() const { return getTypePtr()->getDecl(); }
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for record types.
|
||||
class RecordTypeLoc : public InheritingConcreteTypeLoc<TagTypeLoc,
|
||||
RecordTypeLoc,
|
||||
RecordType> {
|
||||
public:
|
||||
RecordDecl *getDecl() const { return getTypePtr()->getDecl(); }
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for enum types.
|
||||
class EnumTypeLoc : public InheritingConcreteTypeLoc<TagTypeLoc,
|
||||
EnumTypeLoc,
|
||||
EnumType> {
|
||||
public:
|
||||
EnumDecl *getDecl() const { return getTypePtr()->getDecl(); }
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for builtin types.
|
||||
class BuiltinTypeLoc : public TypeSpecTypeLoc<BuiltinTypeLoc,
|
||||
BuiltinType> {
|
||||
class BuiltinTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
BuiltinTypeLoc,
|
||||
BuiltinType> {
|
||||
};
|
||||
|
||||
/// \brief Wrapper for template type parameters.
|
||||
class TemplateTypeParmTypeLoc : public TypeSpecTypeLoc<TemplateTypeParmTypeLoc,
|
||||
TemplateTypeParmType> {
|
||||
class TemplateTypeParmTypeLoc :
|
||||
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
TemplateTypeParmTypeLoc,
|
||||
TemplateTypeParmType> {
|
||||
};
|
||||
|
||||
/// \brief Wrapper for substituted template type parameters.
|
||||
class SubstTemplateTypeParmTypeLoc :
|
||||
public TypeSpecTypeLoc<SubstTemplateTypeParmTypeLoc,
|
||||
SubstTemplateTypeParmType> {
|
||||
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
SubstTemplateTypeParmTypeLoc,
|
||||
SubstTemplateTypeParmType> {
|
||||
};
|
||||
|
||||
|
||||
|
@ -944,63 +996,84 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
// None of these types have proper implementations yet.
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// All of these need proper implementations.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class VectorTypeLoc : public TypeSpecTypeLoc<VectorTypeLoc, VectorType> {
|
||||
// FIXME: size expression and attribute locations (or keyword if we
|
||||
// ever fully support altivec syntax).
|
||||
class VectorTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
VectorTypeLoc,
|
||||
VectorType> {
|
||||
};
|
||||
|
||||
// FIXME: size expression and attribute locations.
|
||||
class ExtVectorTypeLoc : public InheritingConcreteTypeLoc<VectorTypeLoc,
|
||||
ExtVectorTypeLoc,
|
||||
ExtVectorType> {
|
||||
};
|
||||
|
||||
// FIXME: attribute locations.
|
||||
// For some reason, this isn't a subtype of VectorType.
|
||||
class DependentSizedExtVectorTypeLoc :
|
||||
public TypeSpecTypeLoc<DependentSizedExtVectorTypeLoc,
|
||||
DependentSizedExtVectorType> {
|
||||
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
DependentSizedExtVectorTypeLoc,
|
||||
DependentSizedExtVectorType> {
|
||||
};
|
||||
|
||||
class FixedWidthIntTypeLoc : public TypeSpecTypeLoc<FixedWidthIntTypeLoc,
|
||||
FixedWidthIntType> {
|
||||
// FIXME: I'm not sure how you actually specify these; with attributes?
|
||||
class FixedWidthIntTypeLoc :
|
||||
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
FixedWidthIntTypeLoc,
|
||||
FixedWidthIntType> {
|
||||
};
|
||||
|
||||
class ComplexTypeLoc : public TypeSpecTypeLoc<ComplexTypeLoc,
|
||||
ComplexType> {
|
||||
// FIXME: location of the '_Complex' keyword.
|
||||
class ComplexTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
ComplexTypeLoc,
|
||||
ComplexType> {
|
||||
};
|
||||
|
||||
class TypeOfExprTypeLoc : public TypeSpecTypeLoc<TypeOfExprTypeLoc,
|
||||
TypeOfExprType> {
|
||||
// FIXME: location of the 'typeof' and parens (the expression is
|
||||
// carried by the type).
|
||||
class TypeOfExprTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
TypeOfExprTypeLoc,
|
||||
TypeOfExprType> {
|
||||
};
|
||||
|
||||
class TypeOfTypeLoc : public TypeSpecTypeLoc<TypeOfTypeLoc, TypeOfType> {
|
||||
// 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<TypeSpecTypeLoc,
|
||||
TypeOfTypeLoc,
|
||||
TypeOfType> {
|
||||
};
|
||||
|
||||
class DecltypeTypeLoc : public TypeSpecTypeLoc<DecltypeTypeLoc, DecltypeType> {
|
||||
// FIXME: location of the 'decltype' and parens.
|
||||
class DecltypeTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
DecltypeTypeLoc,
|
||||
DecltypeType> {
|
||||
};
|
||||
|
||||
class TagTypeLoc : public TypeSpecTypeLoc<TagTypeLoc, TagType> {
|
||||
// FIXME: location of the tag keyword.
|
||||
class ElaboratedTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
ElaboratedTypeLoc,
|
||||
ElaboratedType> {
|
||||
};
|
||||
|
||||
class RecordTypeLoc : public InheritingConcreteTypeLoc<TagTypeLoc,
|
||||
RecordTypeLoc,
|
||||
RecordType> {
|
||||
// FIXME: locations for the nested name specifier; at the very least,
|
||||
// a SourceRange.
|
||||
class QualifiedNameTypeLoc :
|
||||
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
QualifiedNameTypeLoc,
|
||||
QualifiedNameType> {
|
||||
};
|
||||
|
||||
class EnumTypeLoc : public InheritingConcreteTypeLoc<TagTypeLoc,
|
||||
EnumTypeLoc,
|
||||
EnumType> {
|
||||
};
|
||||
|
||||
class ElaboratedTypeLoc : public TypeSpecTypeLoc<ElaboratedTypeLoc,
|
||||
ElaboratedType> {
|
||||
};
|
||||
|
||||
class QualifiedNameTypeLoc : public TypeSpecTypeLoc<QualifiedNameTypeLoc,
|
||||
QualifiedNameType> {
|
||||
};
|
||||
|
||||
class TypenameTypeLoc : public TypeSpecTypeLoc<TypenameTypeLoc,
|
||||
TypenameType> {
|
||||
// FIXME: locations for the typename keyword and nested name specifier.
|
||||
class TypenameTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
TypenameTypeLoc,
|
||||
TypenameType> {
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -59,30 +59,19 @@ 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<TypeSpecTypeLoc>(pushImpl(T, LocalSize));
|
||||
}
|
||||
|
||||
|
||||
/// Pushes space for a new TypeLoc of the given type. Invalidates
|
||||
/// any TypeLocs previously retrieved from this builder.
|
||||
template <class TyLocType> TyLocType push(QualType T) {
|
||||
#ifndef NDEBUG
|
||||
QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
|
||||
assert(TLast == LastTy &&
|
||||
"mismatch between last type and new type's inner type");
|
||||
LastTy = T;
|
||||
#endif
|
||||
|
||||
size_t LocalSize = cast<TyLocType>(TypeLoc(T, 0)).getLocalDataSize();
|
||||
|
||||
// If we need to grow, grow by a factor of 2.
|
||||
if (LocalSize > Index) {
|
||||
size_t RequiredCapacity = Capacity + (LocalSize - Index);
|
||||
size_t NewCapacity = Capacity * 2;
|
||||
while (RequiredCapacity > NewCapacity)
|
||||
NewCapacity *= 2;
|
||||
grow(NewCapacity);
|
||||
}
|
||||
|
||||
Index -= LocalSize;
|
||||
|
||||
return cast<TyLocType>(TypeLoc(T, &Buffer[Index]));
|
||||
return cast<TyLocType>(pushImpl(T, LocalSize));
|
||||
}
|
||||
|
||||
/// Creates a DeclaratorInfo for the given type.
|
||||
|
@ -97,7 +86,29 @@ class TypeLocBuilder {
|
|||
return DI;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
TypeLoc pushImpl(QualType T, size_t LocalSize) {
|
||||
#ifndef NDEBUG
|
||||
QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
|
||||
assert(TLast == LastTy &&
|
||||
"mismatch between last type and new type's inner type");
|
||||
LastTy = T;
|
||||
#endif
|
||||
|
||||
// If we need to grow, grow by a factor of 2.
|
||||
if (LocalSize > Index) {
|
||||
size_t RequiredCapacity = Capacity + (LocalSize - Index);
|
||||
size_t NewCapacity = Capacity * 2;
|
||||
while (RequiredCapacity > NewCapacity)
|
||||
NewCapacity *= 2;
|
||||
grow(NewCapacity);
|
||||
}
|
||||
|
||||
Index -= LocalSize;
|
||||
|
||||
return TypeLoc(T, &Buffer[Index]);
|
||||
}
|
||||
|
||||
/// Grow to the given capacity.
|
||||
void grow(size_t NewCapacity) {
|
||||
assert(NewCapacity > Capacity);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -260,24 +260,40 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
|
|||
}
|
||||
|
||||
NamedDecl *
|
||||
ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) {
|
||||
ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) {
|
||||
llvm::DenseMap<UsingDecl *, NamedDecl *>::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<UnresolvedUsingValueDecl>(UUD) ||
|
||||
isa<UnresolvedUsingTypenameDecl>(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<UsingDecl>(Pattern) ||
|
||||
isa<UnresolvedUsingValueDecl>(Pattern) ||
|
||||
isa<UnresolvedUsingTypenameDecl>(Pattern)) &&
|
||||
"pattern decl is not a using decl");
|
||||
assert(!InstantiatedFromUsingDecl[Inst] && "pattern already exists");
|
||||
InstantiatedFromUsingDecl[Inst] = Pattern;
|
||||
}
|
||||
|
||||
UsingShadowDecl *
|
||||
ASTContext::getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst) {
|
||||
llvm::DenseMap<UsingShadowDecl*, UsingShadowDecl*>::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<UnresolvedUsingTypenameDecl>(Decl)) {
|
||||
Decl->TypeForDecl = new (*this, TypeAlignment) UnresolvedUsingType(Using);
|
||||
} else
|
||||
assert(false && "TypeDecl without a type?");
|
||||
|
||||
|
|
|
@ -94,3 +94,32 @@ void TypeLoc::initializeImpl(TypeLoc TL, SourceLocation Loc) {
|
|||
TypeLocInitializer(Loc).Visit(TL);
|
||||
} while ((TL = TL.getNextTypeLoc()));
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct TSTChecker : public TypeLocVisitor<TSTChecker, bool> {
|
||||
// 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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -841,6 +841,12 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
|
|||
Out << 'z';
|
||||
}
|
||||
|
||||
// <type> ::= <class-enum-type>
|
||||
// <class-enum-type> ::= <name>
|
||||
void CXXNameMangler::mangleType(const UnresolvedUsingType *T) {
|
||||
mangleName(T->getDecl());
|
||||
}
|
||||
|
||||
// <type> ::= <class-enum-type>
|
||||
// <class-enum-type> ::= <name>
|
||||
void CXXNameMangler::mangleType(const EnumType *T) {
|
||||
|
|
|
@ -1880,6 +1880,10 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
|
|||
Exceptions.data());
|
||||
}
|
||||
|
||||
case pch::TYPE_UNRESOLVED_USING:
|
||||
return Context->getTypeDeclType(
|
||||
cast<UnresolvedUsingTypenameDecl>(GetDecl(Record[0])));
|
||||
|
||||
case pch::TYPE_TYPEDEF:
|
||||
assert(Record.size() == 1 && "incorrect encoding of typedef type");
|
||||
return Context->getTypeDeclType(cast<TypedefDecl>(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++]));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<NestedNameSpecifier *>(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<UsingDecl>(D);
|
||||
|
||||
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(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<CXXRecordDecl>(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<TypeDecl>(R.getFoundDecl())) {
|
||||
if (!R.getAsSingle<TypeDecl>()) {
|
||||
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<TypeDecl>(R.getFoundDecl())) {
|
||||
if (IsInstantiation && R.getAsSingle<TypeDecl>()) {
|
||||
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<NamespaceDecl>(R.getFoundDecl())) {
|
||||
if (R.getAsSingle<NamespaceDecl>()) {
|
||||
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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1064,8 +1064,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
|
|||
Invalid = true;
|
||||
} else if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
|
||||
Fields.push_back(DeclPtrTy::make(Field));
|
||||
else if (UsingDecl *UD = dyn_cast<UsingDecl>(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 =
|
||||
|
|
|
@ -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<UsingDecl>(SemaRef.FindInstantiatedDecl(D->getUsingDecl(),
|
||||
TemplateArgs));
|
||||
NamedDecl *InstTarget =
|
||||
cast<NamedDecl>(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<UsingDecl>(UD),
|
||||
D);
|
||||
SemaRef.Context.setInstantiatedFromUsingDecl(cast<UsingDecl>(UD), D);
|
||||
|
||||
return UD;
|
||||
}
|
||||
|
||||
|
@ -1079,8 +1131,8 @@ Decl * TemplateDeclInstantiator
|
|||
/*instantiation*/ true,
|
||||
/*typename*/ false, SourceLocation());
|
||||
if (UD)
|
||||
SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD),
|
||||
D);
|
||||
SemaRef.Context.setInstantiatedFromUsingDecl(cast<UsingDecl>(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<UsingDecl>(Other))
|
||||
return isInstantiationOf(cast<UsingDecl>(D), Using, Ctx);
|
||||
|
||||
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(Other))
|
||||
return isInstantiationOf(cast<UsingShadowDecl>(D), Shadow, Ctx);
|
||||
|
||||
return D->getDeclName() && isa<NamedDecl>(Other) &&
|
||||
D->getDeclName() == cast<NamedDecl>(Other)->getDeclName();
|
||||
}
|
||||
|
|
|
@ -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<Derived>::TransformFunctionNoProtoType(
|
|||
return Result;
|
||||
}
|
||||
|
||||
template<typename Derived> QualType
|
||||
TreeTransform<Derived>::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<typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB,
|
||||
TypedefTypeLoc TL) {
|
||||
|
@ -5317,6 +5344,30 @@ QualType TreeTransform<Derived>::RebuildFunctionNoProtoType(QualType T) {
|
|||
return SemaRef.Context.getFunctionNoProtoType(T);
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(Decl *D) {
|
||||
assert(D && "no decl found");
|
||||
if (D->isInvalidDecl()) return QualType();
|
||||
|
||||
TypeDecl *Ty;
|
||||
if (isa<UsingDecl>(D)) {
|
||||
UsingDecl *Using = cast<UsingDecl>(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<TypeDecl>((*Using->shadow_begin())->getTargetDecl());
|
||||
|
||||
} else {
|
||||
assert(isa<UnresolvedUsingTypenameDecl>(D) &&
|
||||
"UnresolvedUsingTypenameDecl transformed to non-using decl");
|
||||
Ty = cast<UnresolvedUsingTypenameDecl>(D);
|
||||
}
|
||||
|
||||
return SemaRef.Context.getTypeDeclType(Ty);
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::RebuildTypeOfExprType(ExprArg E) {
|
||||
return SemaRef.BuildTypeofExprType(E.takeAs<Expr>());
|
||||
|
|
|
@ -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 <class T> 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 <class T> 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 <class T> struct B : A<T> {
|
||||
using A<T>::type; // expected-error {{dependent using declaration resolved to type without 'typename'}}
|
||||
using A<T>::hiding;
|
||||
using A<T>::union_member;
|
||||
using A<T>::enumerator;
|
||||
using A<T>::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<T>::hiding local;
|
||||
struct hiding _ = local();
|
||||
}
|
||||
|
||||
void test2() {
|
||||
typedef struct A<T>::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<int>; // expected-note {{in instantiation}}
|
||||
|
||||
template <class T> struct C : A<T> {
|
||||
using typename A<T>::type;
|
||||
using typename A<T>::hiding; // expected-error {{'typename' keyword used on a non-type}}
|
||||
using typename A<T>::union_member; // expected-error {{'typename' keyword used on a non-type}}
|
||||
using typename A<T>::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<int>; // expected-note {{in instantiation}}
|
||||
}
|
|
@ -34,3 +34,14 @@ template<typename T> struct E : A<T> {
|
|||
|
||||
void g() { f(); }
|
||||
};
|
||||
|
||||
namespace test0 {
|
||||
struct Base {
|
||||
int foo;
|
||||
};
|
||||
template<typename T> struct E : Base {
|
||||
using Base::foo;
|
||||
};
|
||||
|
||||
template struct E<int>;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue