diff options
-rw-r--r-- | clang/include/clang/AST/Decl.h | 13 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticKinds.def | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 31 | ||||
-rw-r--r-- | clang/test/SemaCXX/virtuals.cpp | 33 |
4 files changed, 75 insertions, 6 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 7392af6ca54..1d09ea71103 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -648,6 +648,8 @@ private: // NOTE: VC++ treats enums as signed, avoid using the StorageClass enum unsigned SClass : 2; bool IsInline : 1; + bool IsVirtual : 1; + bool IsPure : 1; // Move to DeclGroup when it is implemented. SourceLocation TypeSpecStartLoc; @@ -659,7 +661,8 @@ protected: : ValueDecl(DK, DC, L, N, T, PrevDecl), DeclContext(DK), ParamInfo(0), Body(0), PreviousDeclaration(0), - SClass(S), IsInline(isInline), TypeSpecStartLoc(TSSL) {} + SClass(S), IsInline(isInline), IsVirtual(false), IsPure(false), + TypeSpecStartLoc(TSSL) {} virtual ~FunctionDecl(); virtual void Destroy(ASTContext& C); @@ -692,7 +695,13 @@ public: bool isThisDeclarationADefinition() const { return Body != 0; } void setBody(Stmt *B) { Body = B; } - + + bool isVirtual() { return IsVirtual; } + void setVirtual() { IsVirtual = true; } + + bool isPure() { return IsPure; } + void setPure() { IsPure = true; } + /// getPreviousDeclaration - Return the previous declaration of this /// function. const FunctionDecl *getPreviousDeclaration() const { diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index af721a61281..c8ebe066d1f 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -753,6 +753,10 @@ DIAG(err_not_integral_type_bitfield, ERROR, "bit-field %0 with non-integral type") DIAG(err_member_initialization, ERROR, "%0 can only be initialized if it is a static const integral data member") +DIAG(err_member_function_initialization, ERROR, + "initializer on function does not look like a pure-specifier") +DIAG(err_non_virtual_pure, ERROR, + "%0 is not virtual and cannot be declared pure") DIAG(err_implicit_object_parameter_init, ERROR, "cannot initialize object parameter of type %0 with an expression of type %1") diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index dea3688bdbf..ba4a47d63ec 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -535,6 +535,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, Diag(DS.getVirtualSpecLoc(), diag::err_virtual_non_function); InvalidDecl = true; } else { + cast<CXXMethodDecl>(Member)->setVirtual(); CXXRecordDecl *CurClass = cast<CXXRecordDecl>(CurContext); CurClass->setAggregate(false); CurClass->setPOD(false); @@ -542,6 +543,10 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, } } + // FIXME: The above definition of virtual is not sufficient. A function is + // also virtual if it overrides an already virtual function. This is important + // to do here because it decides the validity of a pure specifier. + if (BitWidth) { // C++ 9.6p2: Only when declaring an unnamed bit-field may the // constant-expression be a value equal to zero. @@ -608,10 +613,28 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, } } else { - // not static member. - Diag(Loc, diag::err_member_initialization) - << Name << Init->getSourceRange(); - InvalidDecl = true; + // not static member. perhaps virtual function? + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) { + IntegerLiteral *IL; + if ((IL = dyn_cast<IntegerLiteral>(Init)) && IL->getValue() == 0 && + Context.getCanonicalType(IL->getType()) == Context.IntTy) { + if (MD->isVirtual()) + MD->setPure(); + else { + Diag(Loc, diag::err_non_virtual_pure) + << Name << Init->getSourceRange(); + InvalidDecl = true; + } + } else { + Diag(Loc, diag::err_member_function_initialization) + << Name << Init->getSourceRange(); + InvalidDecl = true; + } + } else { + Diag(Loc, diag::err_member_initialization) + << Name << Init->getSourceRange(); + InvalidDecl = true; + } } } diff --git a/clang/test/SemaCXX/virtuals.cpp b/clang/test/SemaCXX/virtuals.cpp new file mode 100644 index 00000000000..6cbf3ef15f3 --- /dev/null +++ b/clang/test/SemaCXX/virtuals.cpp @@ -0,0 +1,33 @@ +// RUN: clang -fsyntax-only -verify %s + +class A { + virtual void f(); + virtual void g() = 0; + + void h() = 0; // expected-error {{'h' is not virtual and cannot be declared pure}} + void i() = 1; // expected-error {{initializer on function does not look like a pure-specifier}} + void j() = 0u; // expected-error {{initializer on function does not look like a pure-specifier}} + +public: + A(int); +}; + +class B : public A { + // Needs to recognize that overridden function is virtual. + //void g() = 0; + + // Needs to recognize that function does not override. + //void g(int) = 0; +}; + +// Needs to recognize invalid uses of abstract classes. +/* +A fn(A) +{ + A a; + static_cast<A>(0); + try { + } catch(A) { + } +} +*/ |