[cfe-commits] r67461 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/AST/DeclCXX.h lib/AST/DeclCXX.cpp lib/AST/ExprCXX.cpp lib/Parse/ParseExpr.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/SemaCXX/abstract.cpp
Anders Carlsson
andersca at mac.com
Sat Mar 21 18:52:17 PDT 2009
Author: andersca
Date: Sat Mar 21 20:52:17 2009
New Revision: 67461
URL: http://llvm.org/viewvc/llvm-project?rev=67461&view=rev
Log:
Keep track of whether a class is abstract or not. This is currently only used for the __is_abstract type trait.
Added:
cfe/trunk/test/SemaCXX/abstract.cpp
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/AST/ExprCXX.cpp
cfe/trunk/lib/Parse/ParseExpr.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=67461&r1=67460&r2=67461&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Sat Mar 21 20:52:17 2009
@@ -629,7 +629,7 @@
/// 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
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=67461&r1=67460&r2=67461&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Sat Mar 21 20:52:17 2009
@@ -219,6 +219,10 @@
/// 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 @@
/// [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.
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=67461&r1=67460&r2=67461&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Sat Mar 21 20:52:17 2009
@@ -27,8 +27,8 @@
: 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,
Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=67461&r1=67460&r2=67461&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Sat Mar 21 20:52:17 2009
@@ -214,6 +214,10 @@
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;
}
}
Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=67461&r1=67460&r2=67461&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Sat Mar 21 20:52:17 2009
@@ -768,6 +768,7 @@
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: {
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=67461&r1=67460&r2=67461&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Mar 21 20:52:17 2009
@@ -2224,9 +2224,12 @@
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();
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=67461&r1=67460&r2=67461&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat Mar 21 20:52:17 2009
@@ -705,6 +705,77 @@
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 @@
(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
Added: cfe/trunk/test/SemaCXX/abstract.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/abstract.cpp?rev=67461&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/abstract.cpp (added)
+++ cfe/trunk/test/SemaCXX/abstract.cpp Sat Mar 21 20:52:17 2009
@@ -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");
More information about the cfe-commits
mailing list