]> granicus.if.org Git - clang/commitdiff
Very basic support for pure virtual functions.
authorSebastian Redl <sebastian.redl@getdesigned.at>
Fri, 9 Jan 2009 19:57:06 +0000 (19:57 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Fri, 9 Jan 2009 19:57:06 +0000 (19:57 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62003 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
include/clang/Basic/DiagnosticKinds.def
lib/Sema/SemaDeclCXX.cpp
test/SemaCXX/virtuals.cpp [new file with mode: 0644]

index 7392af6ca54ccb2bef9ec31d19ceb1c0d7163af9..1d09ea71103d0c363d9c0f7461123032364862d0 100644 (file)
@@ -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 {
index af721a6128116b306665e5b51871600fdaaeac0e..c8ebe066d1f9596b2fcad53e617c672a9a1b339d 100644 (file)
@@ -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")
 
index dea3688bdbfb720b4ef18c20ff684b67c61ace8b..ba4a47d63ec9e02f8b25e6f61a0547d74cc30ce5 100644 (file)
@@ -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/test/SemaCXX/virtuals.cpp b/test/SemaCXX/virtuals.cpp
new file mode 100644 (file)
index 0000000..6cbf3ef
--- /dev/null
@@ -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) {
+  }
+}
+*/