From: Sean Hunt Date: Fri, 3 Jun 2011 18:36:49 +0000 (+0000) Subject: Begin implementing a cache of special member lookups. Currently only X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8fd7722fce4e4f9549897699ec3a4c752613b214;p=clang Begin implementing a cache of special member lookups. Currently only destructors are implemented but other special members are on the way, which is where the real benefits of this will be visible. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132572 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index b6c6b5616c..7dc672a41a 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -538,6 +538,14 @@ public: return withFastQualifiers(Qualifiers::Const); } + /// addVolatile - add the specified type qualifier to this QualType. + void addVolatile() { + addFastQualifiers(Qualifiers::Volatile); + } + QualType withVolatile() const { + return withFastQualifiers(Qualifiers::Volatile); + } + void addFastQualifiers(unsigned TQs) { assert(!(TQs & ~Qualifiers::FastMask) && "non-fast qualifier bits set in mask!"); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index a3dd687e3a..280303052b 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -198,6 +198,52 @@ public: typedef std::pair, SourceLocation> UnexpandedParameterPack; +// Holds some information about special member function overloads +// Defined outside Sema so it can be used as a key in a DenseMap. +struct SpecialMemberID { + CXXRecordDecl *D; + unsigned SM : 3; //CXXSpecialMember + bool ConstArg : 1; + bool VolatileArg : 1; + bool RValueThis : 1; + bool ConstThis : 1; + bool VolatileThis : 1; +}; + +} // namespace clang + +namespace llvm { +template <> struct DenseMapInfo { + static inline clang::SpecialMemberID getEmptyKey() { + clang::SpecialMemberID SMI = + {DenseMapInfo::getEmptyKey(), 0,0,0,0,0,0}; + return SMI; + } + static inline clang::SpecialMemberID getTombstoneKey() { + clang::SpecialMemberID SMI = + {DenseMapInfo::getTombstoneKey(), 0,0,0,0,0,0}; + return SMI; + } + static unsigned getHashValue (const clang::SpecialMemberID SMI) { + // Vary higher bits of the pointer for hashing. Attempt to match the + // bit-field representation to reduce masking if the optimizer is awake. + // Note that the LLVM optimizer sleeps through this one. + return (uintptr_t)SMI.D ^ + ((SMI.SM << 24) + (SMI.ConstArg << 27) + (SMI.VolatileArg << 28) + + (SMI.RValueThis << 29) + (SMI.ConstThis << 30) + + (SMI.VolatileThis << 31)); + } + static bool isEqual(const clang::SpecialMemberID LHS, + const clang::SpecialMemberID RHS) { + return LHS.D == RHS.D && LHS.SM == RHS.SM && LHS.ConstArg == RHS.ConstArg && + LHS.VolatileArg == RHS.VolatileArg && + LHS.RValueThis == RHS.RValueThis && LHS.ConstThis == RHS.ConstThis && + LHS.VolatileThis == RHS.VolatileThis; + } +}; +} // namespace llvm + +namespace clang { /// Sema - This implements semantic analysis and AST building for C. class Sema { Sema(const Sema&); // DO NOT IMPLEMENT @@ -600,6 +646,47 @@ public: /// A stack of expression evaluation contexts. llvm::SmallVector ExprEvalContexts; + /// SpecialMemberOverloadResult - The overloading result for a special member + /// function. + /// + /// This is basically a wrapper around PointerIntPair. The lowest bit of the + /// integer is used to determine whether we have a parameter qualification + /// match, the second-lowest is whether we had success in resolving the + /// overload to a unique non-deleted function. + /// + /// The ConstParamMatch bit represents whether, when looking up a copy + /// constructor or assignment operator, we found a potential copy + /// constructor/assignment operator whose first parameter is const-qualified. + /// This is used for determining parameter types of other objects and is + /// utterly meaningless on other types of special members. + class SpecialMemberOverloadResult { + llvm::PointerIntPair Pair; + public: + SpecialMemberOverloadResult(CXXMethodDecl *MD, bool Success, + bool ConstParamMatch) + : Pair(MD, Success | ConstParamMatch << 1) + {} + SpecialMemberOverloadResult() {} + + CXXMethodDecl *getMethod() const { return Pair.getPointer(); } + void setMethod(CXXMethodDecl *MD) { Pair.setPointer(MD); } + + bool hasSuccess() const { return Pair.getInt() & 0x1; } + void setSuccess(bool B) { Pair.setInt(B | hasConstParamMatch() << 1); } + + bool hasConstParamMatch() const { return Pair.getInt() & 0x2; } + void setConstParamMatch(bool B) { Pair.setInt(B << 1 | hasSuccess()); } + }; + + /// \brief A cache of special member function overload resolution results + /// for C++ records. + /// + /// In C++, special member functions of records (such as the copy constructor) + /// are used a lot. As a result, we cache the lookups here so as to make the + /// lookups far easier to perform. + llvm::DenseMap + SpecialMemberCache; + /// \brief Whether the code handled by Sema should be considered a /// complete translation unit or not. /// @@ -1594,6 +1681,14 @@ public: private: bool CppLookupName(LookupResult &R, Scope *S); + SpecialMemberOverloadResult LookupSpecialMember(CXXRecordDecl *D, + CXXSpecialMember SM, + bool ConstArg, + bool VolatileArg, + bool RValueThis, + bool ConstThis, + bool VolatileThis); + public: /// \brief Look up a name, looking for a single declaration. Return /// null if the results were absent, ambiguous, or overloaded. diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 2bfa86cb55..6a441a38d0 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -14,6 +14,7 @@ #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/Overload.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" @@ -2136,6 +2137,51 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, } } +Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *D, + CXXSpecialMember SM, + bool ConstArg, + bool VolatileArg, + bool RValueThis, + bool ConstThis, + bool VolatileThis) { + D = D->getDefinition(); + assert((D && !D->isBeingDefined()) && + "doing special member lookup into record that isn't fully complete"); + if (RValueThis || ConstThis || VolatileThis) + assert((SM == CXXCopyAssignment || SM == CXXMoveAssignment) && + "constructors and destructors always have unqualified lvalue this"); + if (ConstArg || VolatileArg) + assert((SM != CXXDefaultConstructor && SM != CXXDestructor) && + "parameter-less special members can't have qualified arguments"); + + // Check the cache for this member + SpecialMemberID ID = {D, SM, ConstArg, VolatileArg, RValueThis, ConstThis, + VolatileThis}; + SpecialMemberOverloadResult Blank; + llvm::DenseMap::iterator It; + bool New; + + llvm::tie(It, New) = SpecialMemberCache.insert(std::make_pair(ID, Blank)); + SpecialMemberOverloadResult &Result = It->second; + + // This was already cached + if (!New) + return Result; + + if (SM == CXXDestructor) { + if (!D->hasDeclaredDestructor()) + DeclareImplicitDestructor(D); + CXXDestructorDecl *DD = D->getDestructor(); + assert(DD && "record without a destructor"); + Result.setMethod(DD); + Result.setSuccess(DD->isDeleted()); + Result.setConstParamMatch(false); + return Result; + } + + llvm_unreachable("haven't implemented this for non-destructors yet"); +} + /// \brief Look up the constructors for the given class. DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { // If the copy constructor has not yet been declared, do so now. @@ -2153,17 +2199,13 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { /// \brief Look for the destructor of the given class. /// -/// During semantic analysis, this routine should be used in lieu of -/// CXXRecordDecl::getDestructor(). +/// The destructor will be declared if necessary. /// /// \returns The destructor for this class. CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) { - // If the destructor has not yet been declared, do so now. - if (CanDeclareSpecialMemberFunction(Context, Class) && - !Class->hasDeclaredDestructor()) - DeclareImplicitDestructor(Class); - - return Class->getDestructor(); + return cast(LookupSpecialMember(Class, CXXDestructor, + false, false, false, + false, false).getMethod()); } void ADLResult::insert(NamedDecl *New) {