SubclassScope SILDeclRef::getSubclassScope() const { if (!hasDecl()) return SubclassScope::NotApplicable; // If this declaration is a function which goes into a vtable, then it's // symbol must be as visible as its class, because derived classes have to put // all less visible methods of the base class into their vtables. if (auto *CD = dyn_cast<ConstructorDecl>(getDecl())) if (!CD->isRequired()) return SubclassScope::NotApplicable; auto *FD = dyn_cast<FuncDecl>(getDecl()); if (!FD) return SubclassScope::NotApplicable; DeclContext *context = FD->getDeclContext(); // Methods from extensions don't go into vtables (yet). if (isa<ExtensionDecl>(context)) return SubclassScope::NotApplicable; // Various forms of thunks don't either. if (isThunk() || isForeign) return SubclassScope::NotApplicable; // Default arg generators are not visible. if (isDefaultArgGenerator()) return SubclassScope::NotApplicable; auto *classType = context->getSelfClassDecl(); if (!classType || classType->isFinal()) return SubclassScope::NotApplicable; if (FD->isFinal()) return SubclassScope::NotApplicable; assert(FD->getEffectiveAccess() <= classType->getEffectiveAccess() && "class must be as visible as its members"); // FIXME: This is too narrow. Any class with resilient metadata should // probably have this, at least for method overrides that don't add new // vtable entries. if (classType->isResilient()) return SubclassScope::Resilient; switch (classType->getEffectiveAccess()) { case AccessLevel::Private: case AccessLevel::FilePrivate: return SubclassScope::NotApplicable; case AccessLevel::Internal: case AccessLevel::Public: return SubclassScope::Internal; case AccessLevel::Open: return SubclassScope::External; } llvm_unreachable("Unhandled access level in switch."); }
SubclassScope SILDeclRef::getSubclassScope() const { if (!hasDecl()) return SubclassScope::NotApplicable; // If this declaration is a function which goes into a vtable, then it's // symbol must be as visible as its class. Derived classes even have to put // all less visible methods of the base class into their vtables. auto *FD = dyn_cast<AbstractFunctionDecl>(getDecl()); if (!FD) return SubclassScope::NotApplicable; DeclContext *context = FD->getDeclContext(); // Methods from extensions don't go into vtables (yet). if (context->isExtensionContext()) return SubclassScope::NotApplicable; // Various forms of thunks don't either. if (isThunk() || isForeign) return SubclassScope::NotApplicable; // Default arg generators only need to be visible in Swift 3. if (isDefaultArgGenerator() && !context->getASTContext().isSwiftVersion3()) return SubclassScope::NotApplicable; auto *classType = context->getSelfClassDecl(); if (!classType || classType->isFinal()) return SubclassScope::NotApplicable; if (FD->isFinal()) return SubclassScope::NotApplicable; assert(FD->getEffectiveAccess() <= classType->getEffectiveAccess() && "class must be as visible as its members"); switch (classType->getEffectiveAccess()) { case AccessLevel::Private: case AccessLevel::FilePrivate: return SubclassScope::NotApplicable; case AccessLevel::Internal: case AccessLevel::Public: return SubclassScope::Internal; case AccessLevel::Open: return SubclassScope::External; } llvm_unreachable("Unhandled access level in switch."); }
SubclassScope SILDeclRef::getSubclassScope() const { if (!hasDecl()) return SubclassScope::NotApplicable; auto *decl = getDecl(); if (!isa<AbstractFunctionDecl>(decl)) return SubclassScope::NotApplicable; // If this declaration is a function which goes into a vtable, then it's // symbol must be as visible as its class, because derived classes have to put // all less visible methods of the base class into their vtables. if (auto *CD = dyn_cast<ConstructorDecl>(decl)) { // Initializing entry points do not appear in the vtable. if (kind == SILDeclRef::Kind::Initializer) return SubclassScope::NotApplicable; // Non-required convenience inits do not apper in the vtable. if (!CD->isRequired() && !CD->isDesignatedInit()) return SubclassScope::NotApplicable; } else if (isa<DestructorDecl>(decl)) { // Detructors do not appear in the vtable. return SubclassScope::NotApplicable; } else { assert(isa<FuncDecl>(decl)); } DeclContext *context = decl->getDeclContext(); // Methods from extensions don't go in the vtable. if (isa<ExtensionDecl>(context)) return SubclassScope::NotApplicable; // Various forms of thunks don't either. if (isThunk() || isForeign) return SubclassScope::NotApplicable; // Default arg generators don't go in the vtable. if (isDefaultArgGenerator()) return SubclassScope::NotApplicable; // Only non-final methods in non-final classes go in the vtable. auto *classType = context->getSelfClassDecl(); if (!classType || classType->isFinal()) return SubclassScope::NotApplicable; if (decl->isFinal()) return SubclassScope::NotApplicable; assert(decl->getEffectiveAccess() <= classType->getEffectiveAccess() && "class must be as visible as its members"); // FIXME: This is too narrow. Any class with resilient metadata should // probably have this, at least for method overrides that don't add new // vtable entries. if (classType->isResilient()) { if (isa<ConstructorDecl>(decl)) return SubclassScope::NotApplicable; return SubclassScope::Resilient; } switch (classType->getEffectiveAccess()) { case AccessLevel::Private: case AccessLevel::FilePrivate: return SubclassScope::NotApplicable; case AccessLevel::Internal: case AccessLevel::Public: return SubclassScope::Internal; case AccessLevel::Open: return SubclassScope::External; } llvm_unreachable("Unhandled access level in switch."); }