if (CT != Info.AbstractType) return;
// It matched; do some magic.
+ // FIXME: These should be at most warnings. See P0929R2, CWG1640, CWG1646.
if (Sel == Sema::AbstractArrayType) {
Info.S.Diag(Ctx->getLocation(), diag::err_array_of_abstract_type)
<< T << TL.getSourceRange();
}
-/// Check for invalid uses of an abstract type in a method declaration.
+/// Check for invalid uses of an abstract type in a function declaration.
static void CheckAbstractClassUsage(AbstractUsageInfo &Info,
- CXXMethodDecl *MD) {
+ FunctionDecl *FD) {
// No need to do the check on definitions, which require that
// the return/param types be complete.
- if (MD->doesThisDeclarationHaveABody())
+ if (FD->doesThisDeclarationHaveABody())
return;
// For safety's sake, just ignore it if we don't have type source
// information. This should never happen for non-implicit methods,
// but...
- if (TypeSourceInfo *TSI = MD->getTypeSourceInfo())
- Info.CheckType(MD, TSI->getTypeLoc(), Sema::AbstractNone);
+ if (TypeSourceInfo *TSI = FD->getTypeSourceInfo())
+ Info.CheckType(FD, TSI->getTypeLoc(), Sema::AbstractNone);
+}
+
+/// Check for invalid uses of an abstract type in a variable0 declaration.
+static void CheckAbstractClassUsage(AbstractUsageInfo &Info,
+ VarDecl *VD) {
+ // No need to do the check on definitions, which require that
+ // the type is complete.
+ if (VD->isThisDeclarationADefinition())
+ return;
+
+ Info.CheckType(VD, VD->getTypeSourceInfo()->getTypeLoc(),
+ Sema::AbstractVariableType);
}
/// Check for invalid uses of an abstract type within a class definition.
for (auto *D : RD->decls()) {
if (D->isImplicit()) continue;
- // Methods and method templates.
- if (isa<CXXMethodDecl>(D)) {
- CheckAbstractClassUsage(Info, cast<CXXMethodDecl>(D));
- } else if (isa<FunctionTemplateDecl>(D)) {
- FunctionDecl *FD = cast<FunctionTemplateDecl>(D)->getTemplatedDecl();
- CheckAbstractClassUsage(Info, cast<CXXMethodDecl>(FD));
+ // Step through friends to the befriended declaration.
+ if (auto *FD = dyn_cast<FriendDecl>(D)) {
+ D = FD->getFriendDecl();
+ if (!D) continue;
+ }
+
+ // Functions and function templates.
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ CheckAbstractClassUsage(Info, FD);
+ } else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) {
+ CheckAbstractClassUsage(Info, FTD->getTemplatedDecl());
// Fields and static variables.
- } else if (isa<FieldDecl>(D)) {
- FieldDecl *FD = cast<FieldDecl>(D);
+ } else if (auto *FD = dyn_cast<FieldDecl>(D)) {
if (TypeSourceInfo *TSI = FD->getTypeSourceInfo())
Info.CheckType(FD, TSI->getTypeLoc(), Sema::AbstractFieldType);
- } else if (isa<VarDecl>(D)) {
- VarDecl *VD = cast<VarDecl>(D);
- if (TypeSourceInfo *TSI = VD->getTypeSourceInfo())
- Info.CheckType(VD, TSI->getTypeLoc(), Sema::AbstractVariableType);
+ } else if (auto *VD = dyn_cast<VarDecl>(D)) {
+ CheckAbstractClassUsage(Info, VD);
+ } else if (auto *VTD = dyn_cast<VarTemplateDecl>(D)) {
+ CheckAbstractClassUsage(Info, VTD->getTemplatedDecl());
// Nested classes and class templates.
- } else if (isa<CXXRecordDecl>(D)) {
- CheckAbstractClassUsage(Info, cast<CXXRecordDecl>(D));
- } else if (isa<ClassTemplateDecl>(D)) {
- CheckAbstractClassUsage(Info,
- cast<ClassTemplateDecl>(D)->getTemplatedDecl());
+ } else if (auto *RD = dyn_cast<CXXRecordDecl>(D)) {
+ CheckAbstractClassUsage(Info, RD);
+ } else if (auto *CTD = dyn_cast<ClassTemplateDecl>(D)) {
+ CheckAbstractClassUsage(Info, CTD->getTemplatedDecl());
}
}
}
RedundantInit() : A(0) {} // expected-warning {{initializer for virtual base class 'pr16659::A' of abstract class 'RedundantInit' will never be used}}
};
}
+
+struct inline_var { // expected-note {{until the closing '}'}}
+ static inline inline_var v = 0; // expected-error {{incomplete type}} expected-warning {{extension}}
+ virtual void f() = 0;
+};
+
+struct var_template {
+ template<typename T>
+ static var_template v; // expected-error {{abstract class}} expected-warning {{extension}}
+ virtual void f() = 0; // expected-note {{unimplemented}}
+};
+
+struct var_template_def { // expected-note {{until the closing '}'}}
+ template<typename T>
+ static inline var_template_def v = {}; // expected-error {{incomplete type}} expected-warning 2{{extension}}
+ virtual void f() = 0;
+};
+
+struct friend_fn {
+ friend void g(friend_fn); // expected-error {{abstract class}}
+ virtual void f() = 0; // expected-note {{unimplemented}}
+};
+
+struct friend_fn_def {
+ friend void g(friend_fn_def) {} // expected-error {{abstract class}}
+ virtual void f() = 0; // expected-note {{unimplemented}}
+};
+
+struct friend_template {
+ template<typename T>
+ friend void g(friend_template); // expected-error {{abstract class}}
+ virtual void f() = 0; // expected-note {{unimplemented}}
+};
+
+struct friend_template_def {
+ template<typename T>
+ friend void g(friend_template_def) {} // expected-error {{abstract class}}
+ virtual void f() = 0; // expected-note {{unimplemented}}
+};