#ifndef LLVM_CLANG_AST_DECLVISITOR_H
#define LLVM_CLANG_AST_DECLVISITOR_H
+#include "clang/AST/DeclTemplate.h"
+
namespace clang {
#define DISPATCH(NAME, CLASS) \
SourceLocation Loc, SourceRange Range);
std::string getAmbiguousPathsDisplayString(BasePaths &Paths);
- bool RequireNonAbstractType(SourceLocation Loc, QualType T,
- unsigned DiagID, unsigned SelID);
+ enum AbstractDiagSelID {
+ AbstractNone = -1,
+ AbstractReturnType,
+ AbstractParamType,
+ AbstractVariableType,
+ AbstractFieldType
+ };
+
+ bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID,
+ AbstractDiagSelID SelID = AbstractNone);
//===--------------------------------------------------------------------===//
// C++ Overloaded Operators [C++ 13.5]
// The variable can not have an abstract class type.
if (RequireNonAbstractType(D.getIdentifierLoc(), R,
diag::err_abstract_type_in_decl,
- 2 /* variable type */))
+ AbstractVariableType))
InvalidDecl = true;
// The variable can not
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
// Check that the return type is not an abstract class type.
- if (RequireNonAbstractType(D.getIdentifierLoc(),
+ // For record types, this is done by the AbstractClassUsageDiagnoser once
+ // the class has been completely parsed.
+ if (!DC->isRecord() &&
+ RequireNonAbstractType(D.getIdentifierLoc(),
R->getAsFunctionType()->getResultType(),
diag::err_abstract_type_in_decl,
- 0 /* return type */))
- InvalidDecl = true;
+ AbstractReturnType))
+ InvalidDecl = true;
bool isVirtualOkay = false;
FunctionDecl *NewFD;
}
// Parameters can not be abstract class types.
- if (RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType,
+ // For record types, this is done by the AbstractClassUsageDiagnoser once
+ // the class has been completely parsed.
+ if (!CurContext->isRecord() &&
+ RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType,
diag::err_abstract_type_in_decl,
- 1 /* parameter type */))
+ AbstractParamType))
D.setInvalidType(true);
QualType T = adjustParameterType(parmDeclType);
// Fields can not have abstract class types
if (RequireNonAbstractType(Loc, T, diag::err_abstract_type_in_decl,
- 3 /* field type */))
+ AbstractFieldType))
InvalidDecl = true;
// If this is declared as a bit-field, check the bit-field.
#include "SemaInherit.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclVisitor.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Lex/Preprocessor.h"
}
bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
- unsigned DiagID, unsigned SelID) {
+ unsigned DiagID, AbstractDiagSelID SelID) {
if (!getLangOptions().CPlusPlus)
return false;
return true;
}
+namespace {
+ class VISIBILITY_HIDDEN AbstractClassUsageDiagnoser
+ : public DeclVisitor<AbstractClassUsageDiagnoser, bool> {
+ Sema &SemaRef;
+ CXXRecordDecl *AbstractClass;
+
+ public:
+ AbstractClassUsageDiagnoser(Sema& SemaRef, CXXRecordDecl *ac)
+ : SemaRef(SemaRef), AbstractClass(ac) {}
+
+ bool VisitCXXRecordDecl(const CXXRecordDecl *RD) {
+ bool Invalid = false;
+
+ for (CXXRecordDecl::decl_iterator I = RD->decls_begin(),
+ E = RD->decls_end(); I != E; ++I)
+ Invalid |= Visit(*I);
+
+ return Invalid;
+ }
+
+ bool VisitCXXMethodDecl(const CXXMethodDecl *MD) {
+ // Check the return type.
+ QualType RTy = MD->getType()->getAsFunctionType()->getResultType();
+ bool Invalid =
+ SemaRef.RequireNonAbstractType(MD->getLocation(), RTy,
+ diag::err_abstract_type_in_decl,
+ Sema::AbstractReturnType);
+
+ for (CXXMethodDecl::param_const_iterator I = MD->param_begin(),
+ E = MD->param_end(); I != E; ++I) {
+ const ParmVarDecl *VD = *I;
+ Invalid |=
+ SemaRef.RequireNonAbstractType(VD->getLocation(),
+ VD->getOriginalType(),
+ diag::err_abstract_type_in_decl,
+ Sema::AbstractParamType);
+ }
+
+ return Invalid;
+ }
+ };
+}
+
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclTy *TagDecl,
SourceLocation LBrac,
RD->setAbstract(true);
}
+ if (RD->isAbstract())
+ AbstractClassUsageDiagnoser(*this, RD).Visit(RD);
+
if (!Template)
AddImplicitlyDeclaredMembersToClass(RD);
}
diag::err_invalid_incomplete_type_use, FullRange))
return ExprError();
- if (RequireNonAbstractType(TyBeginLoc, Ty,
- diag::err_allocation_of_abstract_type, 0))
+ if (RequireNonAbstractType(TyBeginLoc, Ty,
+ diag::err_allocation_of_abstract_type))
return ExprError();
exprs.release();
return ExprError();
if (RequireNonAbstractType(D.getSourceRange().getBegin(), AllocType,
- diag::err_allocation_of_abstract_type, 0))
+ diag::err_allocation_of_abstract_type))
return ExprError();
QualType ResultType = AllocType->isDependentType()
else if (SemaRef.RequireNonAbstractType(PInst->getLocation(),
PInst->getType(),
diag::err_abstract_type_in_decl,
- 1 /* parameter type */))
+ Sema::AbstractParamType))
PInst->setInvalidDecl();
Params.push_back(PInst);
typedef void (*Func)(C); // expected-error {{parameter type 'C' is an abstract class}}
void t6(Func);
-
+class F {
+ F a() { } // expected-error {{return type 'F' is an abstract class}}
+
+ class D {
+ void f(F c); // expected-error {{parameter type 'F' is an abstract class}}
+ };
+
+ union U {
+ void u(F c); // expected-error {{parameter type 'F' is an abstract class}}
+ };
+
+ virtual void f() = 0; // expected-note {{pure virtual function 'f'}}
+};