]> granicus.if.org Git - clang/commitdiff
Begin implementing a cache of special member lookups. Currently only
authorSean Hunt <scshunt@csclub.uwaterloo.ca>
Fri, 3 Jun 2011 18:36:49 +0000 (18:36 +0000)
committerSean Hunt <scshunt@csclub.uwaterloo.ca>
Fri, 3 Jun 2011 18:36:49 +0000 (18:36 +0000)
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

include/clang/AST/Type.h
include/clang/Sema/Sema.h
lib/Sema/SemaLookup.cpp

index b6c6b5616c933d199425cd6156dfd3174dcaddf9..7dc672a41a79c7d320e604046930d0cd8ca8b2b1 100644 (file)
@@ -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!");
index a3dd687e3a123dc0c95f3e77311687dc5bffca82..280303052b2209038849bbcbc244060b07590a77 100644 (file)
@@ -198,6 +198,52 @@ public:
 typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>,
                   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<clang::SpecialMemberID> {
+  static inline clang::SpecialMemberID getEmptyKey() {
+    clang::SpecialMemberID SMI =
+      {DenseMapInfo<clang::CXXRecordDecl*>::getEmptyKey(), 0,0,0,0,0,0};
+    return SMI;
+  }
+  static inline clang::SpecialMemberID getTombstoneKey() {
+    clang::SpecialMemberID SMI =
+      {DenseMapInfo<clang::CXXRecordDecl*>::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<ExpressionEvaluationContextRecord, 8> 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<CXXMethodDecl*, 2> 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<SpecialMemberID, SpecialMemberOverloadResult>
+    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.
index 2bfa86cb55a79eb939a8d295ad1ed0ebd858654e..6a441a38d0c2765b30517036410ddc5772c69638 100644 (file)
@@ -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<SpecialMemberID, SpecialMemberOverloadResult>::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<CXXDestructorDecl>(LookupSpecialMember(Class, CXXDestructor,
+                                                     false, false, false,
+                                                     false, false).getMethod());
 }
 
 void ADLResult::insert(NamedDecl *New) {