[cfe-commits] r99979 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/DeclCXX.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaInit.cpp lib/Sema/SemaOverload.cpp test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp

John McCall rjmccall at apple.com
Tue Mar 30 18:36:47 PDT 2010


Author: rjmccall
Date: Tue Mar 30 20:36:47 2010
New Revision: 99979

URL: http://llvm.org/viewvc/llvm-project?rev=99979&view=rev
Log:
Regularize support for naming conversion functions in using decls.


Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=99979&r1=99978&r2=99979&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Mar 30 20:36:47 2010
@@ -329,6 +329,10 @@
   /// instantiated or specialized.
   llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*>
     TemplateOrInstantiation;
+
+#ifndef NDEBUG
+  void CheckConversionFunction(NamedDecl *D);
+#endif
   
 protected:
   CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
@@ -550,17 +554,26 @@
     return getConversionFunctions()->replace(Old, New);
   }
 
+  /// Removes a conversion function from this class.  The conversion
+  /// function must currently be a member of this class.  Furthermore,
+  /// this class must currently be in the process of being defined.
+  void removeConversion(const NamedDecl *Old);
+
   /// getVisibleConversionFunctions - get all conversion functions visible
   /// in current class; including conversion function templates.
   const UnresolvedSetImpl *getVisibleConversionFunctions();
 
-  /// addConversionFunction - Add a new conversion function to the
-  /// list of conversion functions.
-  void addConversionFunction(CXXConversionDecl *ConvDecl);
-
-  /// \brief Add a new conversion function template to the list of conversion
-  /// functions.
-  void addConversionFunction(FunctionTemplateDecl *ConvDecl);
+  /// addConversionFunction - Registers a conversion function which
+  /// this class declares directly.
+  void addConversionFunction(NamedDecl *Decl) {
+#ifndef NDEBUG
+    CheckConversionFunction(Decl);
+#endif
+
+    // We intentionally don't use the decl's access here because it
+    // hasn't been set yet.  That's really just a misdesign in Sema.
+    data().Conversions.addDecl(Decl);
+  }
 
   /// isAggregate - Whether this class is an aggregate (C++
   /// [dcl.init.aggr]), which is a class with no user-declared

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=99979&r1=99978&r2=99979&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Mar 30 20:36:47 2010
@@ -308,6 +308,8 @@
 
 static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
   QualType T;
+  if (isa<UsingShadowDecl>(Conv))
+    Conv = cast<UsingShadowDecl>(Conv)->getTargetDecl();
   if (FunctionTemplateDecl *ConvTemp = dyn_cast<FunctionTemplateDecl>(Conv))
     T = ConvTemp->getTemplatedDecl()->getResultType();
   else 
@@ -445,25 +447,44 @@
   return &data().VisibleConversions;
 }
 
-void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) {
-  assert(!ConvDecl->getDescribedFunctionTemplate() &&
-         "Conversion function templates should cast to FunctionTemplateDecl.");
+#ifndef NDEBUG
+void CXXRecordDecl::CheckConversionFunction(NamedDecl *ConvDecl) {
   assert(ConvDecl->getDeclContext() == this &&
          "conversion function does not belong to this record");
 
-  // We intentionally don't use the decl's access here because it
-  // hasn't been set yet.  That's really just a misdesign in Sema.
-  data().Conversions.addDecl(ConvDecl);
+  ConvDecl = ConvDecl->getUnderlyingDecl();
+  if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(ConvDecl)) {
+    assert(isa<CXXConversionDecl>(Temp->getTemplatedDecl()));
+  } else {
+    assert(isa<CXXConversionDecl>(ConvDecl));
+  }
 }
+#endif
 
-void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
-  assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
-         "Function template is not a conversion function template");
-  assert(ConvDecl->getDeclContext() == this &&
-         "conversion function does not belong to this record");
-  data().Conversions.addDecl(ConvDecl);
-}
+void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
+  // This operation is O(N) but extremely rare.  Sema only uses it to
+  // remove UsingShadowDecls in a class that were followed by a direct
+  // declaration, e.g.:
+  //   class A : B {
+  //     using B::operator int;
+  //     operator int();
+  //   };
+  // This is uncommon by itself and even more uncommon in conjunction
+  // with sufficiently large numbers of directly-declared conversions
+  // that asymptotic behavior matters.
+
+  UnresolvedSetImpl &Convs = *getConversionFunctions();
+  for (unsigned I = 0, E = Convs.size(); I != E; ++I) {
+    if (Convs[I].getDecl() == ConvDecl) {
+      Convs.erase(I);
+      assert(std::find(Convs.begin(), Convs.end(), ConvDecl) == Convs.end()
+             && "conversion was found multiple times in unresolved set");
+      return;
+    }
+  }
 
+  llvm_unreachable("conversion not found in set!");
+}
 
 void CXXRecordDecl::setMethodAsVirtual(FunctionDecl *Method) {
   Method->setVirtualAsWritten(true);

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=99979&r1=99978&r2=99979&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Mar 30 20:36:47 2010
@@ -3327,6 +3327,11 @@
     CurContext->addDecl(Shadow);
   Shadow->setAccess(UD->getAccess());
 
+  // Register it as a conversion if appropriate.
+  if (Shadow->getDeclName().getNameKind()
+        == DeclarationName::CXXConversionFunctionName)
+    cast<CXXRecordDecl>(CurContext)->addConversionFunction(Shadow);
+
   if (Orig->isInvalidDecl() || UD->isInvalidDecl())
     Shadow->setInvalidDecl();
 
@@ -3361,6 +3366,10 @@
 /// decl structures are (very reasonably) not designed for removal.
 /// (2) avoids this but is very fiddly and phase-dependent.
 void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {
+  if (Shadow->getDeclName().getNameKind() ==
+        DeclarationName::CXXConversionFunctionName)
+    cast<CXXRecordDecl>(Shadow->getDeclContext())->removeConversion(Shadow);
+
   // Remove it from the DeclContext...
   Shadow->getDeclContext()->removeDecl(Shadow);
 
@@ -3374,7 +3383,7 @@
   Shadow->getUsingDecl()->removeShadowDecl(Shadow);
 
   // TODO: complain somehow if Shadow was used.  It shouldn't
-  // be possible for this to happen, because 
+  // be possible for this to happen, because...?
 }
 
 /// Builds a using declaration.

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=99979&r1=99978&r2=99979&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Mar 30 20:36:47 2010
@@ -1302,17 +1302,21 @@
     QualType Type = Ex->getType();
 
     if (const RecordType *Record = Type->getAs<RecordType>()) {
-      llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions;
+      llvm::SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions;
+
       CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
-      const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions();
-      
+      const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions();      
       for (UnresolvedSetImpl::iterator I = Conversions->begin(),
              E = Conversions->end(); I != E; ++I) {
+        NamedDecl *D = I.getDecl();
+        if (isa<UsingShadowDecl>(D))
+          D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
         // Skip over templated conversion functions; they aren't considered.
-        if (isa<FunctionTemplateDecl>(*I))
+        if (isa<FunctionTemplateDecl>(D))
           continue;
         
-        CXXConversionDecl *Conv = cast<CXXConversionDecl>(*I);
+        CXXConversionDecl *Conv = cast<CXXConversionDecl>(D);
         
         QualType ConvType = Conv->getConversionType().getNonReferenceType();
         if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
@@ -1322,9 +1326,10 @@
       if (ObjectPtrConversions.size() == 1) {
         // We have a single conversion to a pointer-to-object type. Perform
         // that conversion.
+        // TODO: don't redo the conversion calculation.
         Operand.release();
-        if (!PerformImplicitConversion(Ex, 
-                            ObjectPtrConversions.front()->getConversionType(), 
+        if (!PerformImplicitConversion(Ex,
+                            ObjectPtrConversions.front()->getConversionType(),
                                       AA_Converting)) {
           Operand = Owned(Ex);
           Type = Ex->getType();
@@ -1333,10 +1338,8 @@
       else if (ObjectPtrConversions.size() > 1) {
         Diag(StartLoc, diag::err_ambiguous_delete_operand)
               << Type << Ex->getSourceRange();
-        for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) {
-          CXXConversionDecl *Conv = ObjectPtrConversions[i];
-          NoteOverloadCandidate(Conv);
-        }
+        for (unsigned i= 0; i < ObjectPtrConversions.size(); i++)
+          NoteOverloadCandidate(ObjectPtrConversions[i]);
         return ExprError();
       }
     }

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=99979&r1=99978&r2=99979&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Mar 30 20:36:47 2010
@@ -2838,7 +2838,7 @@
         if (ConvTemplate)
           Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
         else
-          Conv = cast<CXXConversionDecl>(*I);
+          Conv = cast<CXXConversionDecl>(D);
         
         if (AllowExplicit || !Conv->isExplicit()) {
           if (ConvTemplate)

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=99979&r1=99978&r2=99979&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Mar 30 20:36:47 2010
@@ -1582,10 +1582,10 @@
 
         CXXConversionDecl *Conv;
         FunctionTemplateDecl *ConvTemplate;
-        if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(*I)))
-          Conv = dyn_cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+        if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(D)))
+          Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
         else
-          Conv = dyn_cast<CXXConversionDecl>(*I);
+          Conv = cast<CXXConversionDecl>(D);
 
         if (AllowExplicit || !Conv->isExplicit()) {
           if (ConvTemplate)
@@ -3310,13 +3310,16 @@
         = ClassDecl->getVisibleConversionFunctions();
       for (UnresolvedSetImpl::iterator I = Conversions->begin(),
              E = Conversions->end(); I != E; ++I) {
+        NamedDecl *D = I.getDecl();
+        if (isa<UsingShadowDecl>(D))
+          D = cast<UsingShadowDecl>(D)->getTargetDecl();
 
         // Skip conversion function templates; they don't tell us anything
         // about which builtin types we can convert to.
-        if (isa<FunctionTemplateDecl>(*I))
+        if (isa<FunctionTemplateDecl>(D))
           continue;
 
-        CXXConversionDecl *Conv = cast<CXXConversionDecl>(*I);
+        CXXConversionDecl *Conv = cast<CXXConversionDecl>(D);
         if (AllowExplicitConversions || !Conv->isExplicit()) {
           AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false, 
                                 VisibleQuals);
@@ -3378,7 +3381,10 @@
     
     for (UnresolvedSetImpl::iterator I = Conversions->begin(),
            E = Conversions->end(); I != E; ++I) {
-      if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(*I)) {
+      NamedDecl *D = I.getDecl();
+      if (isa<UsingShadowDecl>(D))
+        D = cast<UsingShadowDecl>(D)->getTargetDecl();
+      if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(D)) {
         QualType CanTy = Context.getCanonicalType(Conv->getConversionType());
         if (const ReferenceType *ResTypeRef = CanTy->getAs<ReferenceType>())
           CanTy = ResTypeRef->getPointeeType();

Modified: cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp?rev=99979&r1=99978&r2=99979&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp Tue Mar 30 20:36:47 2010
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
 
 // We have to avoid ADL for this test.
 
@@ -65,3 +65,44 @@
     b _2 = B::b();
   }
 }
+
+namespace test2 {
+  class A {
+  protected:
+    operator int();
+    operator bool();
+  };
+
+  class B : private A {
+  protected:
+    using A::operator int; // expected-note {{'declared protected here'}}
+  public:
+    using A::operator bool;
+  };
+
+  int test() {
+    bool b = B();
+    return B(); // expected-error {{'operator int' is a protected member of 'test2::B'}}
+  }
+}
+
+namespace test3 {
+  class A {
+    ~A();
+  };
+
+  class B {
+    friend class C;
+  private:
+    operator A*();
+  };
+
+  class C : public B {
+  public:
+    using B::operator A*;
+  };
+
+  void test() {
+    delete C();
+  }
+}





More information about the cfe-commits mailing list