forked from OSchip/llvm-project
Regularize support for naming conversion functions in using decls.
llvm-svn: 99979
This commit is contained in:
parent
034299ef25
commit
da4458e98f
|
@ -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
|
||||
|
|
|
@ -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::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);
|
||||
setAggregate(false);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue