/// Compare two declarations to determine whether one is a witness of the other. static Comparison compareWitnessAndRequirement(TypeChecker &tc, DeclContext *dc, ValueDecl *decl1, ValueDecl *decl2) { // We only have a witness/requirement pair if exactly one of the declarations // comes from a protocol. auto proto1 = dyn_cast<ProtocolDecl>(decl1->getDeclContext()); auto proto2 = dyn_cast<ProtocolDecl>(decl2->getDeclContext()); if ((bool)proto1 == (bool)proto2) return Comparison::Unordered; // Figure out the protocol, requirement, and potential witness. ProtocolDecl *proto; ValueDecl *req; ValueDecl *potentialWitness; if (proto1) { proto = proto1; req = decl1; potentialWitness = decl2; } else { proto = proto2; req = decl2; potentialWitness = decl1; } // Cannot compare type declarations this way. // FIXME: Use the same type-substitution approach as lookupMemberType. if (isa<TypeDecl>(req)) return Comparison::Unordered; if (!potentialWitness->getDeclContext()->isTypeContext()) return Comparison::Unordered; // Determine whether the type of the witness's context conforms to the // protocol. auto owningType = potentialWitness->getDeclContext()->getDeclaredTypeInContext(); ProtocolConformance *conformance = nullptr; if (!tc.conformsToProtocol(owningType, proto, dc, ConformanceCheckFlags::InExpression, &conformance) || !conformance) return Comparison::Unordered; // If the witness and the potential witness are not the same, there's no // ordering here. if (conformance->getWitness(req, &tc).getDecl() != potentialWitness) return Comparison::Unordered; // We have a requirement/witness match. return proto1? Comparison::Worse : Comparison::Better; }
bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) { using namespace Mangle; if (!isa<FuncDecl>(D) && !D->hasName()) return true; // Ignore. if (D->getModuleContext()->isBuiltinModule()) return true; // Ignore. ValueDecl *VD = const_cast<ValueDecl *>(D); if (ClangNode ClangN = VD->getClangNode()) { llvm::SmallString<128> Buf; if (auto ClangD = ClangN.getAsDecl()) { bool Ignore = clang::index::generateUSRForDecl(ClangD, Buf); if (!Ignore) OS << Buf.str(); return Ignore; } auto &Importer = *D->getASTContext().getClangModuleLoader(); auto ClangMacroInfo = ClangN.getAsMacro(); auto PPRecord = Importer.getClangPreprocessor().getPreprocessingRecord(); assert(PPRecord && "Clang importer should be created with " "-detailed-preprocessing-record option"); auto ClangMacroDef = PPRecord->findMacroDefinition(ClangMacroInfo); bool Ignore = clang::index::generateUSRForMacro( ClangMacroDef, Importer.getClangASTContext().getSourceManager(), Buf); if (!Ignore) OS << Buf.str(); return Ignore; } if (!D->hasType()) return true; // FIXME: mangling 'self' in destructors crashes in mangler. if (isa<ParamDecl>(VD) && isa<DestructorDecl>(VD->getDeclContext())) return true; OS << getUSRSpacePrefix(); Mangler Mangler; if (auto Ctor = dyn_cast<ConstructorDecl>(VD)) { Mangler.mangleConstructorEntity(Ctor, /*isAllocating=*/false, /*uncurryingLevel=*/0); } else if (auto Dtor = dyn_cast<DestructorDecl>(VD)) { Mangler.mangleDestructorEntity(Dtor, /*isDeallocating=*/false); } else if (auto NTD = dyn_cast<NominalTypeDecl>(VD)) { Mangler.mangleNominalType(NTD, Mangler::BindGenerics::None); } else if (isa<TypeAliasDecl>(VD) || isa<AssociatedTypeDecl>(VD)) { Mangler.mangleContextOf(VD, Mangler::BindGenerics::None); Mangler.mangleDeclName(VD); } else { Mangler.mangleEntity(VD, /*uncurryingLevel=*/0); } Mangler.finalize(OS); return false; }
void handlePrimaryAST(ASTUnitRef AstUnit) override { auto &CompInst = AstUnit->getCompilerInstance(); auto &SrcFile = AstUnit->getPrimarySourceFile(); trace::TracedOperation TracedOp; SmallVector<std::pair<unsigned, unsigned>, 8> Ranges; auto Action = [&]() { if (trace::enabled()) { trace::SwiftInvocation SwiftArgs; Invok->raw(SwiftArgs.Args.Args, SwiftArgs.Args.PrimaryFile); trace::initTraceFiles(SwiftArgs, CompInst); TracedOp.start(trace::OperationKind::RelatedIdents, SwiftArgs, {std::make_pair("Offset", std::to_string(Offset))}); } unsigned BufferID = SrcFile.getBufferID().getValue(); SourceLoc Loc = Lexer::getLocForStartOfToken(CompInst.getSourceMgr(), BufferID, Offset); if (Loc.isInvalid()) return; SemaLocResolver Resolver(SrcFile); SemaToken SemaTok = Resolver.resolve(Loc); if (SemaTok.isInvalid()) return; if (SemaTok.IsKeywordArgument) return; ValueDecl *VD = SemaTok.CtorTyRef ? SemaTok.CtorTyRef : SemaTok.ValueD; if (!VD) return; // This was a module reference. // Only accept pointing to an identifier. if (!SemaTok.IsRef && (isa<ConstructorDecl>(VD) || isa<DestructorDecl>(VD) || isa<SubscriptDecl>(VD))) return; if (VD->getName().isOperator()) return; RelatedIdScanner Scanner(SrcFile, BufferID, VD, Ranges); if (DeclContext *LocalDC = VD->getDeclContext()->getLocalContext()) { Scanner.walk(LocalDC); } else { Scanner.walk(SrcFile); } }; Action(); RelatedIdentsInfo Info; Info.Ranges = Ranges; Receiver(Info); }
SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { // Anonymous functions have shared linkage. // FIXME: This should really be the linkage of the parent function. if (getAbstractClosureExpr()) return SILLinkage::Shared; // Native function-local declarations have shared linkage. // FIXME: @objc declarations should be too, but we currently have no way // of marking them "used" other than making them external. ValueDecl *d = getDecl(); DeclContext *moduleContext = d->getDeclContext(); while (!moduleContext->isModuleScopeContext()) { if (!isForeign && moduleContext->isLocalContext()) return SILLinkage::Shared; moduleContext = moduleContext->getParent(); } // Currying and calling convention thunks have shared linkage. if (isThunk()) // If a function declares a @_cdecl name, its native-to-foreign thunk // is exported with the visibility of the function. if (!isNativeToForeignThunk() || !d->getAttrs().hasAttribute<CDeclAttr>()) return SILLinkage::Shared; // Enum constructors are essentially the same as thunks, they are // emitted by need and have shared linkage. if (kind == Kind::EnumElement) return SILLinkage::Shared; // Declarations imported from Clang modules have shared linkage. const SILLinkage ClangLinkage = SILLinkage::Shared; if (isClangImported()) return ClangLinkage; // Declarations that were derived on behalf of types in Clang modules get // shared linkage. if (auto *FD = dyn_cast<FuncDecl>(d)) { if (auto derivedFor = FD->getDerivedForTypeDecl()) if (isa<ClangModuleUnit>(derivedFor->getModuleScopeContext())) return ClangLinkage; } // Otherwise, we have external linkage. switch (d->getEffectiveAccess()) { case Accessibility::Private: return (forDefinition ? SILLinkage::Private : SILLinkage::PrivateExternal); case Accessibility::Internal: return (forDefinition ? SILLinkage::Hidden : SILLinkage::HiddenExternal); default: return (forDefinition ? SILLinkage::Public : SILLinkage::PublicExternal); } }
Optional<SpecializedEmitter> SpecializedEmitter::forDecl(SILGenModule &SGM, SILDeclRef function) { // Only consider standalone declarations in the Builtin module. if (function.kind != SILDeclRef::Kind::Func) return None; if (!function.hasDecl()) return None; ValueDecl *decl = function.getDecl(); if (!isa<BuiltinUnit>(decl->getDeclContext())) return None; auto name = decl->getBaseName().getIdentifier(); const BuiltinInfo &builtin = SGM.M.getBuiltinInfo(name); switch (builtin.ID) { // All the non-SIL, non-type-trait builtins should use the // named-builtin logic, which just emits the builtin as a call to a // builtin function. This includes builtins that aren't even declared // in Builtins.def, i.e. all of the LLVM intrinsics. // // We do this in a separate pass over Builtins.def to avoid creating // a bunch of identical cases. #define BUILTIN(Id, Name, Attrs) \ case BuiltinValueKind::Id: #define BUILTIN_SIL_OPERATION(Id, Name, Overload) #define BUILTIN_SANITIZER_OPERATION(Id, Name, Attrs) #define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name) #include "swift/AST/Builtins.def" case BuiltinValueKind::None: return SpecializedEmitter(name); // Do a second pass over Builtins.def, ignoring all the cases for // which we emitted something above. #define BUILTIN(Id, Name, Attrs) // Use specialized emitters for SIL builtins. #define BUILTIN_SIL_OPERATION(Id, Name, Overload) \ case BuiltinValueKind::Id: \ return SpecializedEmitter(&emitBuiltin##Id); // Sanitizer builtins should never directly be called; they should only // be inserted as instrumentation by SILGen. #define BUILTIN_SANITIZER_OPERATION(Id, Name, Attrs) \ case BuiltinValueKind::Id: \ llvm_unreachable("Sanitizer builtin called directly?"); // Lower away type trait builtins when they're trivially solvable. #define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name) \ case BuiltinValueKind::Id: \ return SpecializedEmitter(&emitBuiltinTypeTrait<&TypeBase::Name, \ BuiltinValueKind::Id>); #include "swift/AST/Builtins.def" } llvm_unreachable("bad builtin kind"); }
SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { // Anonymous functions have shared linkage. // FIXME: This should really be the linkage of the parent function. if (getAbstractClosureExpr()) return SILLinkage::Shared; // Native function-local declarations have shared linkage. // FIXME: @objc declarations should be too, but we currently have no way // of marking them "used" other than making them external. ValueDecl *d = getDecl(); DeclContext *moduleContext = d->getDeclContext(); while (!moduleContext->isModuleScopeContext()) { if (!isForeign && moduleContext->isLocalContext()) return SILLinkage::Shared; moduleContext = moduleContext->getParent(); } // Currying and calling convention thunks have shared linkage. if (isThunk()) // If a function declares a @_cdecl name, its native-to-foreign thunk // is exported with the visibility of the function. if (!isNativeToForeignThunk() || !d->getAttrs().hasAttribute<CDeclAttr>()) return SILLinkage::Shared; // Enum constructors are essentially the same as thunks, they are // emitted by need and have shared linkage. if (isEnumElement()) return SILLinkage::Shared; // Stored property initializers have hidden linkage, since they are // not meant to be used from outside of their module. if (isStoredPropertyInitializer()) return SILLinkage::Hidden; // Declarations imported from Clang modules have shared linkage. const SILLinkage ClangLinkage = SILLinkage::Shared; if (isClangImported()) return ClangLinkage; // Otherwise, we have external linkage. switch (d->getEffectiveAccess()) { case Accessibility::Private: case Accessibility::FilePrivate: return (forDefinition ? SILLinkage::Private : SILLinkage::PrivateExternal); case Accessibility::Internal: return (forDefinition ? SILLinkage::Hidden : SILLinkage::HiddenExternal); default: return (forDefinition ? SILLinkage::Public : SILLinkage::PublicExternal); } }
bool SILDeclRef::isClangImported() const { if (!hasDecl()) return false; ValueDecl *d = getDecl(); DeclContext *moduleContext = d->getDeclContext()->getModuleScopeContext(); if (isa<ClangModuleUnit>(moduleContext)) { if (isClangGenerated()) return true; if (isa<ConstructorDecl>(d) || isa<EnumElementDecl>(d)) return !isForeign; if (auto *FD = dyn_cast<FuncDecl>(d)) if (FD->isAccessor() || isa<NominalTypeDecl>(d->getDeclContext())) return !isForeign; } return false; }
bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) { using namespace Mangle; if (!isa<FuncDecl>(D) && !D->hasName()) return true; // Ignore. if (D->getModuleContext()->isBuiltinModule()) return true; // Ignore. ValueDecl *VD = const_cast<ValueDecl *>(D); auto interpretAsClangNode = [](const ValueDecl *D)->ClangNode { ClangNode ClangN = D->getClangNode(); if (auto ClangD = ClangN.getAsDecl()) { // NSErrorDomain causes the clang enum to be imported like this: // // struct MyError { // enum Code : Int32 { // case errFirst // case errSecond // } // static var errFirst: MyError.Code { get } // static var errSecond: MyError.Code { get } // } // // The clang enum and enum constants are associated with both the // struct/nested enum, and the static vars/enum cases. // But we want unique USRs for the above symbols, so use the clang USR // for the enum and enum cases, and the Swift USR for the struct and vars. // if (isa<clang::EnumDecl>(ClangD)) { if (ClangD->hasAttr<clang::NSErrorDomainAttr>() && isa<StructDecl>(D)) return ClangNode(); } else if (auto *ClangEnumConst = dyn_cast<clang::EnumConstantDecl>(ClangD)) { if (auto *ClangEnum = dyn_cast<clang::EnumDecl>(ClangEnumConst->getDeclContext())) { if (ClangEnum->hasAttr<clang::NSErrorDomainAttr>() && isa<VarDecl>(D)) return ClangNode(); } } } return ClangN; }; if (ClangNode ClangN = interpretAsClangNode(D)) { llvm::SmallString<128> Buf; if (auto ClangD = ClangN.getAsDecl()) { bool Ignore = clang::index::generateUSRForDecl(ClangD, Buf); if (!Ignore) OS << Buf.str(); return Ignore; } auto &Importer = *D->getASTContext().getClangModuleLoader(); auto ClangMacroInfo = ClangN.getAsMacro(); auto PPRecord = Importer.getClangPreprocessor().getPreprocessingRecord(); assert(PPRecord && "Clang importer should be created with " "-detailed-preprocessing-record option"); auto ClangMacroDef = PPRecord->findMacroDefinition(ClangMacroInfo); bool Ignore = clang::index::generateUSRForMacro( ClangMacroDef, Importer.getClangASTContext().getSourceManager(), Buf); if (!Ignore) OS << Buf.str(); return Ignore; } if (!D->hasType()) return true; // FIXME: mangling 'self' in destructors crashes in mangler. if (isa<ParamDecl>(VD) && isa<DestructorDecl>(VD->getDeclContext())) return true; OS << getUSRSpacePrefix(); Mangler Mangler; Mangler.bindGenericParameters(VD->getDeclContext()); if (auto Ctor = dyn_cast<ConstructorDecl>(VD)) { Mangler.mangleConstructorEntity(Ctor, /*isAllocating=*/false, /*uncurryingLevel=*/0); } else if (auto Dtor = dyn_cast<DestructorDecl>(VD)) { Mangler.mangleDestructorEntity(Dtor, /*isDeallocating=*/false); } else if (auto NTD = dyn_cast<NominalTypeDecl>(VD)) { Mangler.mangleNominalType(NTD); } else if (isa<TypeAliasDecl>(VD) || isa<AssociatedTypeDecl>(VD)) { Mangler.mangleContextOf(VD); Mangler.mangleDeclName(VD); } else { Mangler.mangleEntity(VD, /*uncurryingLevel=*/0); } Mangler.finalize(OS); return false; }
SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { if (getAbstractClosureExpr()) { return isSerialized() ? SILLinkage::Shared : SILLinkage::Private; } // Add External to the linkage (e.g. Public -> PublicExternal) if this is a // declaration not a definition. auto maybeAddExternal = [&](SILLinkage linkage) { return forDefinition ? linkage : addExternalToLinkage(linkage); }; // Native function-local declarations have shared linkage. // FIXME: @objc declarations should be too, but we currently have no way // of marking them "used" other than making them external. ValueDecl *d = getDecl(); DeclContext *moduleContext = d->getDeclContext(); while (!moduleContext->isModuleScopeContext()) { if (!isForeign && moduleContext->isLocalContext()) { return isSerialized() ? SILLinkage::Shared : SILLinkage::Private; } moduleContext = moduleContext->getParent(); } // Enum constructors and curry thunks either have private or shared // linkage, dependings are essentially the same as thunks, they are // emitted by need and have shared linkage. if (isEnumElement() || isCurried) { switch (d->getEffectiveAccess()) { case AccessLevel::Private: case AccessLevel::FilePrivate: return maybeAddExternal(SILLinkage::Private); case AccessLevel::Internal: case AccessLevel::Public: case AccessLevel::Open: return SILLinkage::Shared; } } // Calling convention thunks have shared linkage. if (isForeignToNativeThunk()) return SILLinkage::Shared; // If a function declares a @_cdecl name, its native-to-foreign thunk // is exported with the visibility of the function. if (isNativeToForeignThunk() && !d->getAttrs().hasAttribute<CDeclAttr>()) return SILLinkage::Shared; // Declarations imported from Clang modules have shared linkage. if (isClangImported()) return SILLinkage::Shared; // Default argument generators of Public functions have PublicNonABI linkage // if the function was type-checked in Swift 4 mode. if (kind == SILDeclRef::Kind::DefaultArgGenerator) { if (isSerialized()) return maybeAddExternal(SILLinkage::PublicNonABI); } enum class Limit { /// No limit. None, /// The declaration is emitted on-demand; it should end up with internal /// or shared linkage. OnDemand, /// The declaration should never be made public. NeverPublic }; auto limit = Limit::None; // ivar initializers and destroyers are completely contained within the class // from which they come, and never get seen externally. if (isIVarInitializerOrDestroyer()) { limit = Limit::NeverPublic; } // Stored property initializers get the linkage of their containing type. if (isStoredPropertyInitializer()) { // Three cases: // // 1) Type is formally @_fixed_layout. Root initializers can be declared // @inlinable. The property initializer must only reference // public symbols, and is serialized, so we give it PublicNonABI linkage. // // 2) Type is not formally @_fixed_layout and the module is not resilient. // Root initializers can be declared @inlinable. This is the annoying // case. We give the initializer public linkage if the type is public. // // 3) Type is resilient. The property initializer is never public because // root initializers cannot be @inlinable. // // FIXME: Get rid of case 2 somehow. if (isSerialized()) return maybeAddExternal(SILLinkage::PublicNonABI); d = cast<NominalTypeDecl>(d->getDeclContext()); // FIXME: This should always be true. if (d->getDeclContext()->getParentModule()->getResilienceStrategy() == ResilienceStrategy::Resilient) limit = Limit::NeverPublic; } // The global addressor is never public for resilient globals. if (kind == Kind::GlobalAccessor) { if (cast<VarDecl>(d)->isResilient()) { limit = Limit::NeverPublic; } } // Forced-static-dispatch functions are created on-demand and have // at best shared linkage. if (auto fn = dyn_cast<FuncDecl>(d)) { if (fn->hasForcedStaticDispatch()) { limit = Limit::OnDemand; } } auto effectiveAccess = d->getEffectiveAccess(); // Private setter implementations for an internal storage declaration should // be internal as well, so that a dynamically-writable // keypath can be formed from other files. if (auto accessor = dyn_cast<AccessorDecl>(d)) { if (accessor->isSetter() && accessor->getStorage()->getEffectiveAccess() == AccessLevel::Internal) effectiveAccess = AccessLevel::Internal; } switch (effectiveAccess) { case AccessLevel::Private: case AccessLevel::FilePrivate: return maybeAddExternal(SILLinkage::Private); case AccessLevel::Internal: if (limit == Limit::OnDemand) return SILLinkage::Shared; return maybeAddExternal(SILLinkage::Hidden); case AccessLevel::Public: case AccessLevel::Open: if (limit == Limit::OnDemand) return SILLinkage::Shared; if (limit == Limit::NeverPublic) return maybeAddExternal(SILLinkage::Hidden); return maybeAddExternal(SILLinkage::Public); } llvm_unreachable("unhandled access"); }
bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) { using namespace Mangle; if (!D->hasName() && (!isa<FuncDecl>(D) || cast<FuncDecl>(D)->getAccessorKind() == AccessorKind::NotAccessor)) return true; // Ignore. if (D->getModuleContext()->isBuiltinModule()) return true; // Ignore. ValueDecl *VD = const_cast<ValueDecl *>(D); auto interpretAsClangNode = [](const ValueDecl *D)->ClangNode { ClangNode ClangN = D->getClangNode(); if (auto ClangD = ClangN.getAsDecl()) { // NSErrorDomain causes the clang enum to be imported like this: // // struct MyError { // enum Code : Int32 { // case errFirst // case errSecond // } // static var errFirst: MyError.Code { get } // static var errSecond: MyError.Code { get } // } // // The clang enum and enum constants are associated with both the // struct/nested enum, and the static vars/enum cases. // But we want unique USRs for the above symbols, so use the clang USR // for the enum and enum cases, and the Swift USR for the struct and vars. // if (isa<clang::EnumDecl>(ClangD)) { if (ClangD->hasAttr<clang::NSErrorDomainAttr>() && isa<StructDecl>(D)) return ClangNode(); } else if (auto *ClangEnumConst = dyn_cast<clang::EnumConstantDecl>(ClangD)) { if (auto *ClangEnum = dyn_cast<clang::EnumDecl>(ClangEnumConst->getDeclContext())) { if (ClangEnum->hasAttr<clang::NSErrorDomainAttr>() && isa<VarDecl>(D)) return ClangNode(); } } } return ClangN; }; if (ClangNode ClangN = interpretAsClangNode(D)) { llvm::SmallString<128> Buf; if (auto ClangD = ClangN.getAsDecl()) { bool Ignore = clang::index::generateUSRForDecl(ClangD, Buf); if (!Ignore) OS << Buf.str(); return Ignore; } auto &Importer = *D->getASTContext().getClangModuleLoader(); auto ClangMacroInfo = ClangN.getAsMacro(); bool Ignore = clang::index::generateUSRForMacro(D->getNameStr(), ClangMacroInfo->getDefinitionLoc(), Importer.getClangASTContext().getSourceManager(), Buf); if (!Ignore) OS << Buf.str(); return Ignore; } if (ShouldUseObjCUSR(VD)) { return printObjCUSR(VD, OS); } if (!D->hasInterfaceType()) return true; // FIXME: mangling 'self' in destructors crashes in mangler. if (isa<ParamDecl>(VD) && isa<DestructorDecl>(VD->getDeclContext())) return true; NewMangling::ASTMangler NewMangler; std::string Mangled = NewMangler.mangleDeclAsUSR(VD, getUSRSpacePrefix()); OS << Mangled; return false; }