Disallow abstract types where appropriate.
llvm-svn: 67476
This commit is contained in:
parent
75acb0c356
commit
576cc6f725
|
@ -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">;
|
||||
|
|
|
@ -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]
|
||||
//
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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}}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue