diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/include/clang/AST/DeclCXX.h | 25 | ||||
| -rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 47 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 11 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 25 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 18 | ||||
| -rw-r--r-- | clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp | 43 | 
7 files changed, 132 insertions, 39 deletions
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 2ed2cefe5d2..f99b9655f56 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -329,6 +329,10 @@ class CXXRecordDecl : public RecordDecl {    /// 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 @@ public:      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); +  /// addConversionFunction - Registers a conversion function which +  /// this class declares directly. +  void addConversionFunction(NamedDecl *Decl) { +#ifndef NDEBUG +    CheckConversionFunction(Decl); +#endif -  /// \brief Add a new conversion function template to the list of conversion -  /// functions. -  void addConversionFunction(FunctionTemplateDecl *ConvDecl); +    // 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 diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index ed02edd3944..94ed85c7cd2 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -308,6 +308,8 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,  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,26 +447,45 @@ const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() {    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::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; +    } +  } -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); +  llvm_unreachable("conversion not found in set!");  } -  void CXXRecordDecl::setMethodAsVirtual(FunctionDecl *Method) {    Method->setVirtualAsWritten(true);    setAggregate(false); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index dfaa85559bb..3c3786d2173 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -3327,6 +3327,11 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,      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 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,  /// 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 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {    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. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 9baa6ac079b..3befb7e24e5 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1302,17 +1302,21 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,      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 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,        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 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,        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();        }      } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 4612bda7b24..00e2fba5fe2 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2838,7 +2838,7 @@ static void TryUserDefinedConversion(Sema &S,          if (ConvTemplate)            Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());          else -          Conv = cast<CXXConversionDecl>(*I); +          Conv = cast<CXXConversionDecl>(D);          if (AllowExplicit || !Conv->isExplicit()) {            if (ConvTemplate) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 8d3313982c8..be367c3660e 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1582,10 +1582,10 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,          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 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,          = 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 @@ static  Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {      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(); diff --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp index 935f5767889..89e9c897d22 100644 --- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp +++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp @@ -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 @@ namespace Test1 {      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(); +  } +}  | 

