aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DeclCXX.h16
-rw-r--r--include/clang/Basic/DiagnosticKinds.def4
-rw-r--r--lib/Sema/SemaDeclCXX.cpp21
-rw-r--r--lib/Sema/SemaNamedCast.cpp7
-rw-r--r--test/SemaCXX/aggregate-initialization.cpp4
-rw-r--r--test/SemaCXX/class.cpp8
-rw-r--r--test/SemaCXX/dynamic-cast.cpp21
7 files changed, 72 insertions, 9 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 2065677c7a..7be7197080 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -219,6 +219,10 @@ class CXXRecordDecl : public RecordDecl, public DeclContext {
/// Aggregate - True when this class is an aggregate.
bool Aggregate : 1;
+ /// Polymorphic - True when this class is polymorphic, i.e. has at least one
+ /// virtual member or derives from a polymorphic class.
+ bool Polymorphic : 1;
+
/// Bases - Base classes of this class.
/// FIXME: This is wasted space for a union.
CXXBaseSpecifier *Bases;
@@ -238,8 +242,8 @@ class CXXRecordDecl : public RecordDecl, public DeclContext {
SourceLocation L, IdentifierInfo *Id)
: RecordDecl(CXXRecord, TK, DC, L, Id), DeclContext(CXXRecord),
UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
- Aggregate(true), Bases(0), NumBases(0), Constructors(DC, Id),
- Destructor(0) { }
+ Aggregate(true), Polymorphic(false), Bases(0), NumBases(0),
+ Constructors(DC, Id), Destructor(0) { }
~CXXRecordDecl();
@@ -327,6 +331,14 @@ public:
/// [dcl.init.aggr]).
void setAggregate(bool Agg) { Aggregate = Agg; }
+ /// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]),
+ /// which means that the class contains or inherits a virtual function.
+ bool isPolymorphic() const { return Polymorphic; }
+
+ /// setPolymorphic - Set whether this class is polymorphic (C++
+ /// [class.virtual]).
+ void setPolymorphic(bool Poly) { Polymorphic = Poly; }
+
/// viewInheritance - Renders and displays an inheritance diagram
/// for this C++ class and all of its base classes (transitively) using
/// GraphViz.
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index 1972716e1d..fedee73b9c 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -667,6 +667,8 @@ DIAG(err_bad_language, ERROR,
// C++ class members
DIAG(err_storageclass_invalid_for_member, ERROR,
"storage class specified for a member declaration")
+DIAG(err_virtual_non_function, ERROR,
+ "'virtual' can only appear on non-static member functions")
DIAG(err_not_bitfield_type, ERROR,
"cannot declare '%0' to be a bit-field type")
DIAG(err_static_not_bitfield, ERROR,
@@ -1142,6 +1144,8 @@ DIAG(err_bad_dynamic_cast_incomplete, ERROR,
"'%0' is incomplete")
DIAG(err_bad_dynamic_cast_not_ptr, ERROR,
"'%0' is not a pointer")
+DIAG(err_bad_dynamic_cast_not_polymorphic, ERROR,
+ "'%0' is not polymorphic")
DIAG(err_invalid_use_of_function_type, ERROR,
"a function type is not allowed here")
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index ea3c175f16..bdc2fafce8 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -310,6 +310,15 @@ Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
return true;
}
+ // If the base class is polymorphic, the new one is, too.
+ RecordDecl *BaseDecl = BaseType->getAsRecordType()->getDecl();
+ assert(BaseDecl && "Record type has no declaration");
+ BaseDecl = BaseDecl->getDefinition(Context);
+ assert(BaseDecl && "Base type is not incomplete, but has no definition");
+ if (cast<CXXRecordDecl>(BaseDecl)->isPolymorphic()) {
+ cast<CXXRecordDecl>(Decl)->setPolymorphic(true);
+ }
+
// Create the base specifier.
return new CXXBaseSpecifier(SpecifierRange, Virtual,
BaseType->isClassType(), Access, BaseType);
@@ -468,8 +477,16 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
if (isInstField && (AS == AS_private || AS == AS_protected))
cast<CXXRecordDecl>(CurContext)->setAggregate(false);
- // FIXME: If the member is a virtual function, mark it its class as
- // a non-aggregate.
+ if (DS.isVirtualSpecified()) {
+ if (!isFunc || DS.getStorageClassSpec() == DeclSpec::SCS_static) {
+ Diag(DS.getVirtualSpecLoc(), diag::err_virtual_non_function);
+ InvalidDecl = true;
+ } else {
+ CXXRecordDecl *CurClass = cast<CXXRecordDecl>(CurContext);
+ CurClass->setAggregate(false);
+ CurClass->setPolymorphic(true);
+ }
+ }
if (BitWidth) {
// C++ 9.6p2: Only when declaring an unnamed bit-field may the
diff --git a/lib/Sema/SemaNamedCast.cpp b/lib/Sema/SemaNamedCast.cpp
index 980e012246..bf559d620b 100644
--- a/lib/Sema/SemaNamedCast.cpp
+++ b/lib/Sema/SemaNamedCast.cpp
@@ -671,7 +671,12 @@ Sema::CheckDynamicCast(Expr *&SrcExpr, QualType DestType,
}
// C++ 5.2.7p6: Otherwise, v shall be [polymorphic].
- // FIXME: Information not yet available.
+ const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition(Context);
+ assert(SrcDecl && "Definition missing");
+ if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) {
+ Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic,
+ SrcPointee.getUnqualifiedType().getAsString(), SrcExpr->getSourceRange());
+ }
// Done. Everything else is run-time checks.
}
diff --git a/test/SemaCXX/aggregate-initialization.cpp b/test/SemaCXX/aggregate-initialization.cpp
index 855bc27616..75b872feb0 100644
--- a/test/SemaCXX/aggregate-initialization.cpp
+++ b/test/SemaCXX/aggregate-initialization.cpp
@@ -17,10 +17,12 @@ class NonAggr3 {
int m;
};
-// FIXME: virtual functions
struct NonAggr4 {
+ int m;
+ virtual void f();
};
NonAggr1 na1 = { 17 }; // expected-error{{initialization of non-aggregate type 'struct NonAggr1' with an initializer list}}
NonAggr2 na2 = { 17 }; // expected-error{{initialization of non-aggregate type 'struct NonAggr2' with an initializer list}}
NonAggr3 na3 = { 17 }; // expected-error{{initialization of non-aggregate type 'class NonAggr3' with an initializer list}}
+NonAggr4 na4 = { 17 }; // expected-error{{initialization of non-aggregate type 'struct NonAggr4' with an initializer list}}
diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp
index c3886f3922..7eeecdc577 100644
--- a/test/SemaCXX/class.cpp
+++ b/test/SemaCXX/class.cpp
@@ -47,12 +47,16 @@ public:
}
int f1(int p) {
- A z = 6;
- return p + x + this->y + z;
+ A z = 6;
+ return p + x + this->y + z;
}
typedef int A;
+ virtual int vi; // expected-error {{error: 'virtual' can only appear on non-static member functions}}
+ virtual static int vsif(); // expected-error {{error: 'virtual' can only appear on non-static member functions}}
+ virtual int vif();
+
private:
int x,y;
static int sx;
diff --git a/test/SemaCXX/dynamic-cast.cpp b/test/SemaCXX/dynamic-cast.cpp
index 0a4dbc2ae9..5e47b9a0b5 100644
--- a/test/SemaCXX/dynamic-cast.cpp
+++ b/test/SemaCXX/dynamic-cast.cpp
@@ -10,6 +10,15 @@ struct F : B, E {};
struct Incomplete;
+struct Poly
+{
+ virtual void f();
+};
+
+struct PolyDerived : Poly
+{
+};
+
void basic_bad()
{
// ptr -> nonptr
@@ -52,4 +61,14 @@ void up()
(void)dynamic_cast<A&>(*((F*)0)); // expected-error {{ambiguous conversion from derived class 'struct F' to base class 'struct A':\n struct F -> struct B -> struct A\n struct F -> struct E -> struct A}}
}
-// FIXME: Other test cases require recognition of polymorphic classes.
+void poly()
+{
+ (void)dynamic_cast<A*>((Poly*)0);
+ (void)dynamic_cast<A&>(*((Poly*)0));
+ (void)dynamic_cast<A*>((PolyDerived*)0);
+ (void)dynamic_cast<A&>(*((PolyDerived*)0));
+
+ // Not polymorphic source
+ (void)dynamic_cast<Poly*>((A*)0); // expected-error {{'struct A' is not polymorphic}}
+ (void)dynamic_cast<PolyDerived&>(*((A*)0)); // expected-error {{'struct A' is not polymorphic}}
+}