forked from OSchip/llvm-project
Keep track of whether a class is abstract or not. This is currently only used for the __is_abstract type trait.
llvm-svn: 67461
This commit is contained in:
parent
e09ad90882
commit
7cbd8fb6b0
|
@ -629,7 +629,7 @@ public:
|
|||
|
||||
/// Whether this virtual function is pure, i.e. makes the containing class
|
||||
/// abstract.
|
||||
bool isPure() { return IsPure; }
|
||||
bool isPure() const { return IsPure; }
|
||||
void setPure() { IsPure = true; }
|
||||
|
||||
/// \brief Whether this function has a prototype, either because one
|
||||
|
|
|
@ -219,6 +219,10 @@ class CXXRecordDecl : public RecordDecl {
|
|||
/// virtual member or derives from a polymorphic class.
|
||||
bool Polymorphic : 1;
|
||||
|
||||
/// Abstract - True when this class is abstract, i.e. has at least one
|
||||
/// pure virtual function, (that can come from a base class).
|
||||
bool Abstract : 1;
|
||||
|
||||
/// Bases - Base classes of this class.
|
||||
/// FIXME: This is wasted space for a union.
|
||||
CXXBaseSpecifier *Bases;
|
||||
|
@ -352,6 +356,13 @@ public:
|
|||
/// [class.virtual]).
|
||||
void setPolymorphic(bool Poly) { Polymorphic = Poly; }
|
||||
|
||||
/// isAbstract - Whether this class is abstract (C++ [class.abstract]),
|
||||
/// which means that the class contains or inherits a pure virtual function.
|
||||
bool isAbstract() const { return Abstract; }
|
||||
|
||||
/// setAbstract - Set whether this class is abstract (C++ [class.abstract])
|
||||
void setAbstract(bool Abs) { Abstract = Abs; }
|
||||
|
||||
/// viewInheritance - Renders and displays an inheritance diagram
|
||||
/// for this C++ class and all of its base classes (transitively) using
|
||||
/// GraphViz.
|
||||
|
|
|
@ -27,8 +27,8 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
|
|||
: RecordDecl(K, TK, DC, L, Id),
|
||||
UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
|
||||
UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
|
||||
Aggregate(true), PlainOldData(true), Polymorphic(false), Bases(0),
|
||||
NumBases(0), Conversions(DC, DeclarationName()) { }
|
||||
Aggregate(true), PlainOldData(true), Polymorphic(false), Abstract(false),
|
||||
Bases(0), NumBases(0), Conversions(DC, DeclarationName()) { }
|
||||
|
||||
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
|
|
|
@ -214,6 +214,10 @@ bool UnaryTypeTraitExpr::EvaluateTrait() const {
|
|||
return cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic();
|
||||
}
|
||||
return false;
|
||||
case UTT_IsAbstract:
|
||||
if (const RecordType *RT = QueriedType->getAsRecordType())
|
||||
return cast<CXXRecordDecl>(RT->getDecl())->isAbstract();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -768,6 +768,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
|||
case tok::kw___is_enum:
|
||||
case tok::kw___is_union:
|
||||
case tok::kw___is_polymorphic:
|
||||
case tok::kw___is_abstract:
|
||||
return ParseUnaryTypeTrait();
|
||||
|
||||
case tok::at: {
|
||||
|
|
|
@ -2224,9 +2224,12 @@ void Sema::AddInitializerToDecl(DeclTy *dcl, ExprArg init, bool DirectInit) {
|
|||
Expr *Init = static_cast<Expr *>(init.get());
|
||||
if ((IL = dyn_cast<IntegerLiteral>(Init)) && IL->getValue() == 0 &&
|
||||
Context.getCanonicalType(IL->getType()) == Context.IntTy) {
|
||||
if (Method->isVirtual())
|
||||
if (Method->isVirtual()) {
|
||||
Method->setPure();
|
||||
else {
|
||||
|
||||
// A class is abstract if at least one function is pure virtual.
|
||||
cast<CXXRecordDecl>(CurContext)->setAbstract(true);
|
||||
} else {
|
||||
Diag(Method->getLocation(), diag::err_non_virtual_pure)
|
||||
<< Method->getDeclName() << Init->getSourceRange();
|
||||
Method->setInvalidDecl();
|
||||
|
|
|
@ -705,6 +705,77 @@ Sema::ActOnMemInitializer(DeclTy *ConstructorD,
|
|||
return new CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, NumArgs);
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// PureVirtualMethodCollector - traverses a class and its superclasses
|
||||
/// and determines if it has any pure virtual methods.
|
||||
class VISIBILITY_HIDDEN PureVirtualMethodCollector {
|
||||
ASTContext &Context;
|
||||
|
||||
typedef llvm::SmallVector<const CXXMethodDecl*, 8> MethodList;
|
||||
MethodList Methods;
|
||||
|
||||
void Collect(const CXXRecordDecl* RD, MethodList& Methods);
|
||||
|
||||
public:
|
||||
PureVirtualMethodCollector(ASTContext &Ctx, const CXXRecordDecl* RD)
|
||||
: Context(Ctx) {
|
||||
|
||||
MethodList List;
|
||||
Collect(RD, List);
|
||||
|
||||
// Copy the temporary list to methods, and make sure to ignore any
|
||||
// null entries.
|
||||
for (size_t i = 0, e = List.size(); i != e; ++i) {
|
||||
if (List[i])
|
||||
Methods.push_back(List[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool empty() const { return Methods.empty(); }
|
||||
};
|
||||
|
||||
void PureVirtualMethodCollector::Collect(const CXXRecordDecl* RD,
|
||||
MethodList& Methods) {
|
||||
// First, collect the pure virtual methods for the base classes.
|
||||
for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(),
|
||||
BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) {
|
||||
if (const RecordType *RT = Base->getType()->getAsRecordType()) {
|
||||
const CXXRecordDecl *BaseDecl
|
||||
= cast<CXXRecordDecl>(RT->getDecl());
|
||||
if (BaseDecl && BaseDecl->isAbstract())
|
||||
Collect(BaseDecl, Methods);
|
||||
}
|
||||
}
|
||||
|
||||
// Next, zero out any pure virtual methods that this class overrides.
|
||||
for (size_t i = 0, e = Methods.size(); i != e; ++i) {
|
||||
const CXXMethodDecl *VMD = dyn_cast_or_null<CXXMethodDecl>(Methods[i]);
|
||||
if (!VMD)
|
||||
continue;
|
||||
|
||||
DeclContext::lookup_const_iterator I, E;
|
||||
for (llvm::tie(I, E) = RD->lookup(VMD->getDeclName()); I != E; ++I) {
|
||||
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*I)) {
|
||||
if (Context.getCanonicalType(MD->getType()) ==
|
||||
Context.getCanonicalType(VMD->getType())) {
|
||||
// We did find a matching method, which means that this is not a
|
||||
// pure virtual method in the current class. Zero it out.
|
||||
Methods[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, add pure virtual methods from this class.
|
||||
for (RecordDecl::decl_iterator i = RD->decls_begin(), e = RD->decls_end();
|
||||
i != e; ++i) {
|
||||
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*i)) {
|
||||
if (MD->isPure())
|
||||
Methods.push_back(MD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
|
||||
DeclTy *TagDecl,
|
||||
|
@ -715,8 +786,17 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
|
|||
(DeclTy**)FieldCollector->getCurFields(),
|
||||
FieldCollector->getCurNumFields(), LBrac, RBrac, 0);
|
||||
|
||||
CXXRecordDecl *RD = cast<CXXRecordDecl>((Decl*)TagDecl);
|
||||
if (!RD->isAbstract()) {
|
||||
// Collect all the pure virtual methods and see if this is an abstract
|
||||
// class after all.
|
||||
PureVirtualMethodCollector Collector(Context, RD);
|
||||
if (!Collector.empty())
|
||||
RD->setAbstract(true);
|
||||
}
|
||||
|
||||
if (!Template)
|
||||
AddImplicitlyDeclaredMembersToClass(cast<CXXRecordDecl>((Decl*)TagDecl));
|
||||
AddImplicitlyDeclaredMembersToClass(RD);
|
||||
}
|
||||
|
||||
/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
// RUN: clang -fsyntax-only -verify %s -std=c++0x
|
||||
|
||||
#ifndef __GXX_EXPERIMENTAL_CXX0X__
|
||||
#define __CONCAT(__X, __Y) __CONCAT1(__X, __Y)
|
||||
#define __CONCAT1(__X, __Y) __X ## __Y
|
||||
|
||||
#define static_assert(__b, __m) \
|
||||
typedef int __CONCAT(__sa, __LINE__)[__b ? 1 : -1]
|
||||
#endif
|
||||
|
||||
class C {
|
||||
virtual void f() = 0;
|
||||
};
|
||||
|
||||
static_assert(__is_abstract(C), "C has a pure virtual function");
|
||||
|
||||
class D : C {
|
||||
};
|
||||
|
||||
static_assert(__is_abstract(D), "D inherits from an abstract class");
|
||||
|
||||
class E : D {
|
||||
virtual void f();
|
||||
};
|
||||
|
||||
static_assert(!__is_abstract(E), "E inherits from an abstract class but implements f");
|
Loading…
Reference in New Issue