Fix "using typename" and the instantiation of non-dependent using declarations.

llvm-svn: 90614
This commit is contained in:
John McCall 2009-12-04 22:46:56 +00:00
parent 9e2792690b
commit b96ec56871
20 changed files with 675 additions and 122 deletions

View File

@ -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);

View File

@ -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:

View File

@ -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> {
};
}

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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?");

View File

@ -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);
}

View File

@ -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;

View File

@ -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) {

View File

@ -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++]));
}

View File

@ -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);
}

View File

@ -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,

View File

@ -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,

View File

@ -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)

View File

@ -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 =

View File

@ -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();
}

View File

@ -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>());

View File

@ -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}}
}

View File

@ -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>;
}