diff options
-rw-r--r-- | include/clang/AST/DeclCXX.h | 16 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 4 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 21 | ||||
-rw-r--r-- | lib/Sema/SemaNamedCast.cpp | 7 | ||||
-rw-r--r-- | test/SemaCXX/aggregate-initialization.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/class.cpp | 8 | ||||
-rw-r--r-- | test/SemaCXX/dynamic-cast.cpp | 21 |
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}} +} |