summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnders Carlsson <andersca@mac.com>2009-03-22 20:18:17 +0000
committerAnders Carlsson <andersca@mac.com>2009-03-22 20:18:17 +0000
commit4681ebd429846ed98e7beaf49934fa347ff22152 (patch)
treeb6cc31b6b66002b1e0fb9bca6c9ab6a495cd176d
parentff75e1db95a53c7606e0bb114cf9adc59ab3d7f6 (diff)
downloadclang-4681ebd429846ed98e7beaf49934fa347ff22152.tar.gz
Disallow abstract types where appropriate.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67476 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td6
-rw-r--r--lib/Sema/Sema.h9
-rw-r--r--lib/Sema/SemaDecl.cpp27
-rw-r--r--lib/Sema/SemaDeclCXX.cpp46
-rw-r--r--test/SemaCXX/abstract.cpp10
5 files changed, 94 insertions, 4 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index f3961844db..945ab5986f 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -219,6 +219,12 @@ def err_static_assert_expression_is_not_constant : Error<
"static_assert expression is not an integral constant expression">;
def err_static_assert_failed : Error<"static_assert failed \"%0\"">;
+def err_abstract_type_in_decl : Error<
+ "%select{return|parameter|variable|field}0 type %1 is an abstract class">;
+
+def note_pure_virtual_function : Note<
+ "pure virtual function %0">;
+
// C++ name lookup
def err_incomplete_nested_name_spec : Error<
"incomplete type %0 named in nested name specifier">;
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 4082440f42..64cc088e96 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -151,6 +151,13 @@ public:
/// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes.
llvm::OwningPtr<CXXFieldCollector> FieldCollector;
+ typedef llvm::SmallPtrSet<const CXXRecordDecl*, 8> RecordDeclSetTy;
+
+ /// PureVirtualClassDiagSet - a set of class declarations which we have
+ /// emitted a list of pure virtual functions. Used to prevent emitting the
+ /// same list more than once.
+ llvm::OwningPtr<RecordDeclSetTy> PureVirtualClassDiagSet;
+
/// \brief A mapping from external names to the most recent
/// locally-scoped external declaration with that name.
///
@@ -1627,6 +1634,8 @@ public:
SourceLocation Loc, SourceRange Range);
std::string getAmbiguousPathsDisplayString(BasePaths &Paths);
+ bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned SelID);
+
//===--------------------------------------------------------------------===//
// C++ Overloaded Operators [C++ 13.5]
//
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 7b45d5232f..255fd6c5ba 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1637,6 +1637,12 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
} else if (SC == VarDecl::None)
SC = VarDecl::Static;
}
+
+ // The variable can not have an abstract class type.
+ if (RequireNonAbstractType(D.getIdentifierLoc(), R, 2 /* variable type */))
+ InvalidDecl = true;
+
+ // The variable can not
NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
II, R, SC,
// FIXME: Move to DeclGroup...
@@ -1804,6 +1810,12 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
+ // Check that the return type is not an abstract class type.
+ if (RequireNonAbstractType(D.getIdentifierLoc(),
+ R->getAsFunctionType()->getResultType(),
+ 0 /* return type */))
+ InvalidDecl = true;
+
bool isVirtualOkay = false;
FunctionDecl *NewFD;
if (D.getKind() == Declarator::DK_Constructor) {
@@ -1977,8 +1989,15 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Diag(Param->getLocation(), diag::ext_param_typedef_of_void);
}
} else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) {
- for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
- Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param);
+ for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
+ ParmVarDecl *PVD = (ParmVarDecl *)FTI.ArgInfo[i].Param;
+
+ // Function parameters cannot have abstract class types.
+ if (RequireNonAbstractType(PVD->getLocation(), PVD->getType(),
+ 1 /* parameter type */))
+ InvalidDecl = true;
+ Params.push_back(PVD);
+ }
}
NewFD->setParams(Context, &Params[0], Params.size());
@@ -3512,6 +3531,10 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
}
}
+ // Fields can not have abstract class types
+ if (RequireNonAbstractType(Loc, T, 3 /* field type */))
+ InvalidDecl = true;
+
// If this is declared as a bit-field, check the bit-field.
if (BitWidth && VerifyBitField(Loc, II, T, BitWidth)) {
InvalidDecl = true;
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index b18b6c8f84..60d1692156 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -731,7 +731,10 @@ namespace {
}
}
- bool empty() const { return Methods.empty(); }
+ bool empty() const { return Methods.empty(); }
+
+ MethodList::const_iterator methods_begin() { return Methods.begin(); }
+ MethodList::const_iterator methods_end() { return Methods.end(); }
};
void PureVirtualMethodCollector::Collect(const CXXRecordDecl* RD,
@@ -777,6 +780,47 @@ namespace {
}
}
+bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
+ unsigned SelID) {
+
+ if (!getLangOptions().CPlusPlus)
+ return false;
+
+ const RecordType *RT = T->getAsRecordType();
+ if (!RT)
+ return false;
+
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD)
+ return false;
+
+ if (!RD->isAbstract())
+ return false;
+
+ Diag(Loc, diag::err_abstract_type_in_decl) << SelID << RD->getDeclName();
+
+ // Check if we've already emitted the list of pure virtual functions for this
+ // class.
+ if (PureVirtualClassDiagSet && PureVirtualClassDiagSet->count(RD))
+ return true;
+
+ PureVirtualMethodCollector Collector(Context, RD);
+
+ for (PureVirtualMethodCollector::MethodList::const_iterator I =
+ Collector.methods_begin(), E = Collector.methods_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ Diag(MD->getLocation(), diag::note_pure_virtual_function) <<
+ MD->getDeclName();
+ }
+
+ if (!PureVirtualClassDiagSet)
+ PureVirtualClassDiagSet.reset(new RecordDeclSetTy);
+ PureVirtualClassDiagSet->insert(RD);
+
+ return true;
+}
+
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclTy *TagDecl,
SourceLocation LBrac,
diff --git a/test/SemaCXX/abstract.cpp b/test/SemaCXX/abstract.cpp
index a7a52116da..e3c7651efb 100644
--- a/test/SemaCXX/abstract.cpp
+++ b/test/SemaCXX/abstract.cpp
@@ -9,7 +9,7 @@
#endif
class C {
- virtual void f() = 0;
+ virtual void f() = 0; // expected-note {{pure virtual function 'f'}}
};
static_assert(__is_abstract(C), "C has a pure virtual function");
@@ -24,3 +24,11 @@ class E : D {
};
static_assert(!__is_abstract(E), "E inherits from an abstract class but implements f");
+
+C c; // expected-error {{variable type 'C' is an abstract class}}
+void t1(C c); // expected-error {{parameter type 'C' is an abstract class}}
+void t2(C); // expected-error {{parameter type 'C' is an abstract class}}
+
+struct S {
+ C c; // expected-error {{field type 'C' is an abstract class}}
+};