From: John McCall Date: Fri, 28 May 2010 06:08:54 +0000 (+0000) Subject: Optimize and complete associated-class-and-namespace collection from X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fa4edcf2639415bd3430a61e6d5bfc71d5b8981e;p=clang Optimize and complete associated-class-and-namespace collection from a type. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104938 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 4555a86e01..16d7305867 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1590,7 +1590,7 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, // argument-dependent lookup with an argument of type T // (C++ [basic.lookup.koenig]p2). static void -addAssociatedClassesAndNamespaces(QualType T, +addAssociatedClassesAndNamespaces(QualType Ty, ASTContext &Context, Sema::AssociatedNamespaceSet &AssociatedNamespaces, Sema::AssociatedClassSet &AssociatedClasses) { @@ -1604,109 +1604,139 @@ addAssociatedClassesAndNamespaces(QualType T, // argument). Typedef names and using-declarations used to specify // the types do not contribute to this set. The sets of namespaces // and classes are determined in the following way: - T = Context.getCanonicalType(T).getUnqualifiedType(); - // -- If T is a pointer to U or an array of U, its associated - // namespaces and classes are those associated with U. - // - // We handle this by unwrapping pointer and array types immediately, - // to avoid unnecessary recursion. + llvm::SmallVector Queue; + const Type *T = Ty->getCanonicalTypeInternal().getTypePtr(); + while (true) { - if (const PointerType *Ptr = T->getAs()) - T = Ptr->getPointeeType(); - else if (const ArrayType *Ptr = Context.getAsArrayType(T)) - T = Ptr->getElementType(); - else + switch (T->getTypeClass()) { + +#define TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: +#define ABSTRACT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + // T is canonical. We can also ignore dependent types because + // we don't need to do ADL at the definition point, but if we + // wanted to implement template export (or if we find some other + // use for associated classes and namespaces...) this would be + // wrong. break; - } - // -- If T is a fundamental type, its associated sets of - // namespaces and classes are both empty. - if (T->getAs()) - return; + // -- If T is a pointer to U or an array of U, its associated + // namespaces and classes are those associated with U. + case Type::Pointer: + T = cast(T)->getPointeeType().getTypePtr(); + continue; + case Type::ConstantArray: + case Type::IncompleteArray: + case Type::VariableArray: + T = cast(T)->getElementType().getTypePtr(); + continue; - // -- If T is a class type (including unions), its associated - // classes are: the class itself; the class of which it is a - // member, if any; and its direct and indirect base - // classes. Its associated namespaces are the namespaces in - // which its associated classes are defined. - if (const RecordType *ClassType = T->getAs()) - if (CXXRecordDecl *ClassDecl - = dyn_cast(ClassType->getDecl())) { - addAssociatedClassesAndNamespaces(ClassDecl, Context, + // -- If T is a fundamental type, its associated sets of + // namespaces and classes are both empty. + case Type::Builtin: + break; + + // -- If T is a class type (including unions), its associated + // classes are: the class itself; the class of which it is a + // member, if any; and its direct and indirect base + // classes. Its associated namespaces are the namespaces in + // which its associated classes are defined. + case Type::Record: { + CXXRecordDecl *Class + = cast(cast(T)->getDecl()); + addAssociatedClassesAndNamespaces(Class, Context, AssociatedNamespaces, AssociatedClasses); - return; + break; } - // -- If T is an enumeration type, its associated namespace is - // the namespace in which it is defined. If it is class - // member, its associated class is the member’s class; else - // it has no associated class. - if (const EnumType *EnumT = T->getAs()) { - EnumDecl *Enum = EnumT->getDecl(); + // -- If T is an enumeration type, its associated namespace is + // the namespace in which it is defined. If it is class + // member, its associated class is the member’s class; else + // it has no associated class. + case Type::Enum: { + EnumDecl *Enum = cast(T)->getDecl(); - DeclContext *Ctx = Enum->getDeclContext(); - if (CXXRecordDecl *EnclosingClass = dyn_cast(Ctx)) - AssociatedClasses.insert(EnclosingClass); + DeclContext *Ctx = Enum->getDeclContext(); + if (CXXRecordDecl *EnclosingClass = dyn_cast(Ctx)) + AssociatedClasses.insert(EnclosingClass); - // Add the associated namespace for this class. - CollectEnclosingNamespace(AssociatedNamespaces, Ctx); + // Add the associated namespace for this class. + CollectEnclosingNamespace(AssociatedNamespaces, Ctx); - return; - } + break; + } - // -- If T is a function type, its associated namespaces and - // classes are those associated with the function parameter - // types and those associated with the return type. - if (const FunctionType *FnType = T->getAs()) { - // Return type - addAssociatedClassesAndNamespaces(FnType->getResultType(), - Context, - AssociatedNamespaces, AssociatedClasses); + // -- If T is a function type, its associated namespaces and + // classes are those associated with the function parameter + // types and those associated with the return type. + case Type::FunctionProto: { + const FunctionProtoType *Proto = cast(T); + for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), + ArgEnd = Proto->arg_type_end(); + Arg != ArgEnd; ++Arg) + Queue.push_back(Arg->getTypePtr()); + // fallthrough + } + case Type::FunctionNoProto: { + const FunctionType *FnType = cast(T); + T = FnType->getResultType().getTypePtr(); + continue; + } - const FunctionProtoType *Proto = dyn_cast(FnType); - if (!Proto) - return; + // -- If T is a pointer to a member function of a class X, its + // associated namespaces and classes are those associated + // with the function parameter types and return type, + // together with those associated with X. + // + // -- If T is a pointer to a data member of class X, its + // associated namespaces and classes are those associated + // with the member type together with those associated with + // X. + case Type::MemberPointer: { + const MemberPointerType *MemberPtr = cast(T); + + // Queue up the class type into which this points. + Queue.push_back(MemberPtr->getClass()); + + // And directly continue with the pointee type. + T = MemberPtr->getPointeeType().getTypePtr(); + continue; + } - // Argument types - for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), - ArgEnd = Proto->arg_type_end(); - Arg != ArgEnd; ++Arg) - addAssociatedClassesAndNamespaces(*Arg, Context, - AssociatedNamespaces, AssociatedClasses); + // As an extension, treat this like a normal pointer. + case Type::BlockPointer: + T = cast(T)->getPointeeType().getTypePtr(); + continue; - return; - } + // References aren't covered by the standard, but that's such an + // obvious defect that we cover them anyway. + case Type::LValueReference: + case Type::RValueReference: + T = cast(T)->getPointeeType().getTypePtr(); + continue; - // -- If T is a pointer to a member function of a class X, its - // associated namespaces and classes are those associated - // with the function parameter types and return type, - // together with those associated with X. - // - // -- If T is a pointer to a data member of class X, its - // associated namespaces and classes are those associated - // with the member type together with those associated with - // X. - if (const MemberPointerType *MemberPtr = T->getAs()) { - // Handle the type that the pointer to member points to. - addAssociatedClassesAndNamespaces(MemberPtr->getPointeeType(), - Context, - AssociatedNamespaces, - AssociatedClasses); - - // Handle the class type into which this points. - if (const RecordType *Class = MemberPtr->getClass()->getAs()) - addAssociatedClassesAndNamespaces(cast(Class->getDecl()), - Context, - AssociatedNamespaces, - AssociatedClasses); + // These are fundamental types. + case Type::Vector: + case Type::ExtVector: + case Type::Complex: + break; - return; - } + // These are ignored by ADL. + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::ObjCObjectPointer: + break; + } - // FIXME: What about block pointers? - // FIXME: What about Objective-C message sends? + if (Queue.empty()) break; + T = Queue.back(); + Queue.pop_back(); + } } /// \brief Find the associated classes and namespaces for