diff options
Diffstat (limited to 'clang/lib')
-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 |
5 files changed, 71 insertions, 32 deletions
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(); |