/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS) { assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); if (SS.isInvalid()) return true; DeclContext *DC = computeDeclContext(SS, true); if (!DC) return true; // Before we enter a declarator's context, we need to make sure that // it is a complete declaration context. if (!DC->isDependentContext() && RequireCompleteDeclContext(SS, DC)) return true; EnterDeclaratorContext(S, DC); // Rebuild the nested name specifier for the new scope. if (DC->isDependentContext()) RebuildNestedNameSpecifierInCurrentInstantiation(SS); return false; }
/// Ensure that the outer generic parameters of the given generic /// context have been configured. static void configureOuterGenericParams(const GenericContext *dc) { auto genericParams = dc->getGenericParams(); // If we already configured the outer parameters, we're done. if (genericParams && genericParams->getOuterParameters()) return; DeclContext *outerDC = dc->getParent(); while (!outerDC->isModuleScopeContext()) { if (auto outerDecl = outerDC->getAsDecl()) { if (auto outerGenericDC = outerDecl->getAsGenericContext()) { if (genericParams) genericParams->setOuterParameters(outerGenericDC->getGenericParams()); configureOuterGenericParams(outerGenericDC); return; } } outerDC = outerDC->getParent(); } }
DeclContext *DeclContext::getInnermostTypeContext() { DeclContext *Result = this; while (true) { switch (Result->getContextKind()) { case DeclContextKind::AbstractClosureExpr: case DeclContextKind::Initializer: case DeclContextKind::TopLevelCodeDecl: case DeclContextKind::AbstractFunctionDecl: case DeclContextKind::SerializedLocal: Result = Result->getParent(); continue; case DeclContextKind::Module: case DeclContextKind::FileUnit: return nullptr; case DeclContextKind::ExtensionDecl: case DeclContextKind::NominalTypeDecl: return Result; } } }
DeclContext::lookup_result DeclContext::noload_lookup(DeclarationName Name) { assert(DeclKind != Decl::LinkageSpec && "Should not perform lookups into linkage specs!"); if (!hasExternalVisibleStorage()) return lookup(Name); DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) return PrimaryContext->noload_lookup(Name); StoredDeclsMap *Map = LookupPtr.getPointer(); if (LookupPtr.getInt()) { // Carefully build the lookup map, without deserializing anything. SmallVector<DeclContext *, 2> Contexts; collectAllContexts(Contexts); for (unsigned I = 0, N = Contexts.size(); I != N; ++I) buildLookupImpl<&DeclContext::noload_decls_begin, &DeclContext::noload_decls_end>(Contexts[I]); // We no longer have any lazy decls. LookupPtr.setInt(false); // There may now be names for which we have local decls but are // missing the external decls. FIXME: Just set the hasExternalDecls // flag on those names that have external decls. NeedToReconcileExternalVisibleStorage = true; Map = LookupPtr.getPointer(); } if (!Map) return lookup_result(lookup_iterator(0), lookup_iterator(0)); StoredDeclsMap::iterator I = Map->find(Name); return I != Map->end() ? I->second.getLookupResult() : lookup_result(lookup_iterator(0), lookup_iterator(0)); }
static void GCRewriteFinalize(MigrationPass &pass) { ASTContext &Ctx = pass.Ctx; TransformActions &TA = pass.TA; DeclContext *DC = Ctx.getTranslationUnitDecl(); Selector FinalizeSel = Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize")); typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl> impl_iterator; for (impl_iterator I = impl_iterator(DC->decls_begin()), E = impl_iterator(DC->decls_end()); I != E; ++I) { for (ObjCImplementationDecl::instmeth_iterator MI = I->instmeth_begin(), ME = I->instmeth_end(); MI != ME; ++MI) { ObjCMethodDecl *MD = *MI; if (!MD->hasBody()) continue; if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) { ObjCMethodDecl *FinalizeM = MD; Transaction Trans(TA); TA.insert(FinalizeM->getSourceRange().getBegin(), "#if !__has_feature(objc_arc)\n"); CharSourceRange::getTokenRange(FinalizeM->getSourceRange()); const SourceManager &SM = pass.Ctx.getSourceManager(); const LangOptions &LangOpts = pass.Ctx.getLangOpts(); bool Invalid; std::string str = "\n#endif\n"; str += Lexer::getSourceText( CharSourceRange::getTokenRange(FinalizeM->getSourceRange()), SM, LangOpts, &Invalid); TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str); break; } } } }
static SILFunction::ClassVisibility_t getClassVisibility(SILDeclRef constant) { if (!constant.hasDecl()) return SILFunction::NotRelevant; // 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>(constant.getDecl()); if (!FD) return SILFunction::NotRelevant; DeclContext *context = FD->getDeclContext(); // Methods from extensions don't go into vtables (yet). if (context->isExtensionContext()) return SILFunction::NotRelevant; auto *classType = context->getAsClassOrClassExtensionContext(); if (!classType || classType->isFinal()) return SILFunction::NotRelevant; if (FD->isFinal() && !FD->getOverriddenDecl()) return SILFunction::NotRelevant; assert(FD->getEffectiveAccess() <= classType->getEffectiveAccess() && "class must be as visible as its members"); switch (classType->getEffectiveAccess()) { case Accessibility::Private: case Accessibility::FilePrivate: return SILFunction::NotRelevant; case Accessibility::Internal: return SILFunction::InternalClass; case Accessibility::Public: return SILFunction::PublicClass; } }
DeclContext::lookup_result DeclContext::lookup(DeclarationName Name) { assert(DeclKind != Decl::LinkageSpec && "Should not perform lookups into linkage specs!"); DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) return PrimaryContext->lookup(Name); if (hasExternalVisibleStorage()) { // If a PCH has a result for this name, and we have a local declaration, we // will have imported the PCH result when adding the local declaration. // FIXME: For modules, we could have had more declarations added by module // imoprts since we saw the declaration of the local name. if (StoredDeclsMap *Map = LookupPtr.getPointer()) { StoredDeclsMap::iterator I = Map->find(Name); if (I != Map->end()) return I->second.getLookupResult(); } ExternalASTSource *Source = getParentASTContext().getExternalSource(); return Source->FindExternalVisibleDeclsByName(this, Name); } StoredDeclsMap *Map = LookupPtr.getPointer(); if (LookupPtr.getInt()) Map = buildLookup(); if (!Map) return lookup_result(lookup_iterator(0), lookup_iterator(0)); StoredDeclsMap::iterator I = Map->find(Name); if (I == Map->end()) return lookup_result(lookup_iterator(0), lookup_iterator(0)); return I->second.getLookupResult(); }
static void removeDeallocMethod(MigrationPass &pass) { ASTContext &Ctx = pass.Ctx; TransformActions &TA = pass.TA; DeclContext *DC = Ctx.getTranslationUnitDecl(); typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl> impl_iterator; for (impl_iterator I = impl_iterator(DC->decls_begin()), E = impl_iterator(DC->decls_end()); I != E; ++I) { for (ObjCImplementationDecl::instmeth_iterator MI = (*I)->instmeth_begin(), ME = (*I)->instmeth_end(); MI != ME; ++MI) { ObjCMethodDecl *MD = *MI; if (MD->getMethodFamily() == OMF_dealloc) { if (MD->hasBody() && isBodyEmpty(MD->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) { Transaction Trans(TA); TA.remove(MD->getSourceRange()); } break; } } } }
void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) { // FIXME: This feels like a hack. Should DeclarationName support // template-ids, or is there a better way to keep specializations // from being visible? if (isa<ClassTemplateSpecializationDecl>(D)) return; DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) { PrimaryContext->makeDeclVisibleInContext(D, Recoverable); return; } // If we already have a lookup data structure, perform the insertion // into it. Otherwise, be lazy and don't build that structure until // someone asks for it. if (LookupPtr || !Recoverable) makeDeclVisibleInContextImpl(D); // If we are a transparent context, insert into our parent context, // too. This operation is recursive. if (isTransparentContext()) getParent()->makeDeclVisibleInContext(D, Recoverable); }
bool ClassTemplateToClass::hasUsedNameDecl( ClassTemplatePartialSpecializationDecl *PartialD) { if (!PartialD->isCompleteDefinition()) return false; SmallPtrSet<NamedDecl *, 8> Params; TemplateParameterList *PartialTPList = PartialD->getTemplateParameters(); for (unsigned PI = 0; PI < PartialTPList->size(); ++PI) { NamedDecl *ND = PartialTPList->getParam(PI); if (dyn_cast<NonTypeTemplateParmDecl>(ND)) continue; Params.insert(ND); } TemplateParameterTypeVisitor ParamVisitor(Context); // Skip visiting parameters and arguments for (CXXRecordDecl::base_class_iterator I = PartialD->bases_begin(), E = PartialD->bases_end(); I != E; ++I) { ParamVisitor.TraverseType(I->getType()); } DeclContext *Ctx = dyn_cast<DeclContext>(PartialD); for (DeclContext::decl_iterator DI = Ctx->decls_begin(), DE = Ctx->decls_end(); DI != DE; ++DI) { ParamVisitor.TraverseDecl(*DI); } for (SmallPtrSet<NamedDecl *, 8>::iterator I = Params.begin(), E = Params.end(); I != E; ++I) { if (ParamVisitor.isAUsedParameter(*I)) return true; } return false; }
DeclContext::lookup_result DeclContext::lookup(IdentifierInfo &Name) { DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) // FIXME: not needed? return PrimaryContext->lookup(Name); #if 0 // FIXME: modules. eventually. resync this part from clang. if (hasExternalVisibleStorage()) { // If a PCH has a result for this name, and we have a local declaration, we // will have imported the PCH result when adding the local declaration. // FIXME: For modules, we could have had more declarations added by module // imoprts since we saw the declaration of the local name. if (StoredDeclsMap *Map = LookupPtr.getPointer()) { StoredDeclsMap::iterator I = Map->find(&Name); if (I != Map->end()) return I->second.getLookupResult(); } ExternalASTSource *Source = getParentASTContext().getExternalSource(); return Source->FindExternalVisibleDeclsByName(this, Name); } #endif StoredDeclsMap *Map = LookupPtr.getPointer(); if (LookupPtr.getInt()) Map = buildLookup(); if (!Map) return lookup_result(lookup_iterator(0), lookup_iterator(0)); StoredDeclsMap::iterator I = Map->find(&Name); if (I == Map->end()) return lookup_result(lookup_iterator(0), lookup_iterator(0)); return I->second.getLookupResult(); }
bool mismatch(SubstitutableType *paramType, TypeBase *argType, Type sugaredFirstType) { Type type = paramType; if (type->is<GenericTypeParamType>()) { assert(dc); type = dc->mapTypeIntoContext(paramType); } if (auto archetype = type->getAs<ArchetypeType>()) { auto existing = archetypesMap[archetype]; if (existing) return existing->isEqual(argType); archetypesMap[archetype] = argType; return true; } return false; }
CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange, bool KnownDependent) { DeclContext *DC = CurContext; while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext())) DC = DC->getParent(); // Start constructing the lambda class. CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC, IntroducerRange.getBegin(), KnownDependent); DC->addDecl(Class); return Class; }
void clang::FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind, intptr_t Val, const char *Modifier, unsigned ModLen, const char *Argument, unsigned ArgLen, const Diagnostic::ArgumentValue *PrevArgs, unsigned NumPrevArgs, llvm::SmallVectorImpl<char> &Output, void *Cookie) { ASTContext &Context = *static_cast<ASTContext*>(Cookie); std::string S; bool NeedQuotes = true; switch (Kind) { default: assert(0 && "unknown ArgumentKind"); case Diagnostic::ak_qualtype: { assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for QualType argument"); QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val))); S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs); NeedQuotes = false; break; } case Diagnostic::ak_declarationname: { DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); S = N.getAsString(); if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0) S = '+' + S; else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) && ArgLen==0) S = '-' + S; else assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for DeclarationName argument"); break; } case Diagnostic::ak_nameddecl: { bool Qualified; if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0) Qualified = true; else { assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for NamedDecl* argument"); Qualified = false; } reinterpret_cast<NamedDecl*>(Val)-> getNameForDiagnostic(S, Context.PrintingPolicy, Qualified); break; } case Diagnostic::ak_nestednamespec: { llvm::raw_string_ostream OS(S); reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS, Context.PrintingPolicy); NeedQuotes = false; break; } case Diagnostic::ak_declcontext: { DeclContext *DC = reinterpret_cast<DeclContext *> (Val); assert(DC && "Should never have a null declaration context"); if (DC->isTranslationUnit()) { // FIXME: Get these strings from some localized place if (Context.getLangOptions().CPlusPlus) S = "the global namespace"; else S = "the global scope"; } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) { S = ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type), PrevArgs, NumPrevArgs); } else { // FIXME: Get these strings from some localized place NamedDecl *ND = cast<NamedDecl>(DC); if (isa<NamespaceDecl>(ND)) S += "namespace "; else if (isa<ObjCMethodDecl>(ND)) S += "method "; else if (isa<FunctionDecl>(ND)) S += "function "; S += "'"; ND->getNameForDiagnostic(S, Context.PrintingPolicy, true); S += "'"; } NeedQuotes = false; break; } } if (NeedQuotes) Output.push_back('\''); Output.append(S.begin(), S.end()); if (NeedQuotes) Output.push_back('\''); }
/// Build a new nested-name-specifier for "identifier::", as described /// by ActOnCXXNestedNameSpecifier. /// /// \param S Scope in which the nested-name-specifier occurs. /// \param IdInfo Parser information about an identifier in the /// nested-name-spec. /// \param EnteringContext If true, enter the context specified by the /// nested-name-specifier. /// \param SS Optional nested name specifier preceding the identifier. /// \param ScopeLookupResult Provides the result of name lookup within the /// scope of the nested-name-specifier that was computed at template /// definition time. /// \param ErrorRecoveryLookup Specifies if the method is called to improve /// error recovery and what kind of recovery is performed. /// \param IsCorrectedToColon If not null, suggestion of replace '::' -> ':' /// are allowed. The bool value pointed by this parameter is set to /// 'true' if the identifier is treated as if it was followed by ':', /// not '::'. /// \param OnlyNamespace If true, only considers namespaces in lookup. /// /// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in /// that it contains an extra parameter \p ScopeLookupResult, which provides /// the result of name lookup within the scope of the nested-name-specifier /// that was computed at template definition time. /// /// If ErrorRecoveryLookup is true, then this call is used to improve error /// recovery. This means that it should not emit diagnostics, it should /// just return true on failure. It also means it should only return a valid /// scope if it *knows* that the result is correct. It should not return in a /// dependent context, for example. Nor will it extend \p SS with the scope /// specifier. bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, bool EnteringContext, CXXScopeSpec &SS, NamedDecl *ScopeLookupResult, bool ErrorRecoveryLookup, bool *IsCorrectedToColon, bool OnlyNamespace) { if (IdInfo.Identifier->isEditorPlaceholder()) return true; LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc, OnlyNamespace ? LookupNamespaceName : LookupNestedNameSpecifierName); QualType ObjectType = GetTypeFromParser(IdInfo.ObjectType); // Determine where to perform name lookup DeclContext *LookupCtx = nullptr; bool isDependent = false; if (IsCorrectedToColon) *IsCorrectedToColon = false; if (!ObjectType.isNull()) { // This nested-name-specifier occurs in a member access expression, e.g., // x->B::f, and we are looking into the type of the object. assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); isDependent = ObjectType->isDependentType(); } else if (SS.isSet()) { // This nested-name-specifier occurs after another nested-name-specifier, // so look into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = isDependentScopeSpecifier(SS); Found.setContextRange(SS.getRange()); } bool ObjectTypeSearchedInScope = false; if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we // computed, which is either the type of the base of a member access // expression or the declaration context associated with a prior // nested-name-specifier. // The declaration context must be complete. if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS, LookupCtx)) return true; LookupQualifiedName(Found, LookupCtx); if (!ObjectType.isNull() && Found.empty()) { // C++ [basic.lookup.classref]p4: // If the id-expression in a class member access is a qualified-id of // the form // // class-name-or-namespace-name::... // // the class-name-or-namespace-name following the . or -> operator is // looked up both in the context of the entire postfix-expression and in // the scope of the class of the object expression. If the name is found // only in the scope of the class of the object expression, the name // shall refer to a class-name. If the name is found only in the // context of the entire postfix-expression, the name shall refer to a // class-name or namespace-name. [...] // // Qualified name lookup into a class will not find a namespace-name, // so we do not need to diagnose that case specifically. However, // this qualified name lookup may find nothing. In that case, perform // unqualified name lookup in the given scope (if available) or // reconstruct the result from when name lookup was performed at template // definition time. if (S) LookupName(Found, S); else if (ScopeLookupResult) Found.addDecl(ScopeLookupResult); ObjectTypeSearchedInScope = true; } } else if (!isDependent) { // Perform unqualified name lookup in the current scope. LookupName(Found, S); } if (Found.isAmbiguous()) return true; // If we performed lookup into a dependent context and did not find anything, // that's fine: just build a dependent nested-name-specifier. if (Found.empty() && isDependent && !(LookupCtx && LookupCtx->isRecord() && (!cast<CXXRecordDecl>(LookupCtx)->hasDefinition() || !cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()))) { // Don't speculate if we're just trying to improve error recovery. if (ErrorRecoveryLookup) return true; // We were not able to compute the declaration context for a dependent // base object type or prior nested-name-specifier, so this // nested-name-specifier refers to an unknown specialization. Just build // a dependent nested-name-specifier. SS.Extend(Context, IdInfo.Identifier, IdInfo.IdentifierLoc, IdInfo.CCLoc); return false; } if (Found.empty() && !ErrorRecoveryLookup) { // If identifier is not found as class-name-or-namespace-name, but is found // as other entity, don't look for typos. LookupResult R(*this, Found.getLookupNameInfo(), LookupOrdinaryName); if (LookupCtx) LookupQualifiedName(R, LookupCtx); else if (S && !isDependent) LookupName(R, S); if (!R.empty()) { // Don't diagnose problems with this speculative lookup. R.suppressDiagnostics(); // The identifier is found in ordinary lookup. If correction to colon is // allowed, suggest replacement to ':'. if (IsCorrectedToColon) { *IsCorrectedToColon = true; Diag(IdInfo.CCLoc, diag::err_nested_name_spec_is_not_class) << IdInfo.Identifier << getLangOpts().CPlusPlus << FixItHint::CreateReplacement(IdInfo.CCLoc, ":"); if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) Diag(ND->getLocation(), diag::note_declared_at); return true; } // Replacement '::' -> ':' is not allowed, just issue respective error. Diag(R.getNameLoc(), OnlyNamespace ? unsigned(diag::err_expected_namespace_name) : unsigned(diag::err_expected_class_or_namespace)) << IdInfo.Identifier << getLangOpts().CPlusPlus; if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) Diag(ND->getLocation(), diag::note_entity_declared_at) << IdInfo.Identifier; return true; } } if (Found.empty() && !ErrorRecoveryLookup && !getLangOpts().MSVCCompat) { // We haven't found anything, and we're not recovering from a // different kind of error, so look for typos. DeclarationName Name = Found.getLookupName(); Found.clear(); NestedNameSpecifierValidatorCCC CCC(*this); if (TypoCorrection Corrected = CorrectTypo( Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS, CCC, CTK_ErrorRecovery, LookupCtx, EnteringContext)) { if (LookupCtx) { bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && Name.getAsString() == Corrected.getAsString(getLangOpts()); if (DroppedSpecifier) SS.clear(); diagnoseTypo(Corrected, PDiag(diag::err_no_member_suggest) << Name << LookupCtx << DroppedSpecifier << SS.getRange()); } else diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest) << Name); if (Corrected.getCorrectionSpecifier()) SS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(), SourceRange(Found.getNameLoc())); if (NamedDecl *ND = Corrected.getFoundDecl()) Found.addDecl(ND); Found.setLookupName(Corrected.getCorrection()); } else { Found.setLookupName(IdInfo.Identifier); } } NamedDecl *SD = Found.isSingleResult() ? Found.getRepresentativeDecl() : nullptr; bool IsExtension = false; bool AcceptSpec = isAcceptableNestedNameSpecifier(SD, &IsExtension); if (!AcceptSpec && IsExtension) { AcceptSpec = true; Diag(IdInfo.IdentifierLoc, diag::ext_nested_name_spec_is_enum); } if (AcceptSpec) { if (!ObjectType.isNull() && !ObjectTypeSearchedInScope && !getLangOpts().CPlusPlus11) { // C++03 [basic.lookup.classref]p4: // [...] If the name is found in both contexts, the // class-name-or-namespace-name shall refer to the same entity. // // We already found the name in the scope of the object. Now, look // into the current scope (the scope of the postfix-expression) to // see if we can find the same name there. As above, if there is no // scope, reconstruct the result from the template instantiation itself. // // Note that C++11 does *not* perform this redundant lookup. NamedDecl *OuterDecl; if (S) { LookupResult FoundOuter(*this, IdInfo.Identifier, IdInfo.IdentifierLoc, LookupNestedNameSpecifierName); LookupName(FoundOuter, S); OuterDecl = FoundOuter.getAsSingle<NamedDecl>(); } else OuterDecl = ScopeLookupResult; if (isAcceptableNestedNameSpecifier(OuterDecl) && OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() && (!isa<TypeDecl>(OuterDecl) || !isa<TypeDecl>(SD) || !Context.hasSameType( Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)), Context.getTypeDeclType(cast<TypeDecl>(SD))))) { if (ErrorRecoveryLookup) return true; Diag(IdInfo.IdentifierLoc, diag::err_nested_name_member_ref_lookup_ambiguous) << IdInfo.Identifier; Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type) << ObjectType; Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope); // Fall through so that we'll pick the name we found in the object // type, since that's probably what the user wanted anyway. } } if (auto *TD = dyn_cast_or_null<TypedefNameDecl>(SD)) MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); // If we're just performing this lookup for error-recovery purposes, // don't extend the nested-name-specifier. Just return now. if (ErrorRecoveryLookup) return false; // The use of a nested name specifier may trigger deprecation warnings. DiagnoseUseOfDecl(SD, IdInfo.CCLoc); if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD)) { SS.Extend(Context, Namespace, IdInfo.IdentifierLoc, IdInfo.CCLoc); return false; } if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD)) { SS.Extend(Context, Alias, IdInfo.IdentifierLoc, IdInfo.CCLoc); return false; } QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD->getUnderlyingDecl())); TypeLocBuilder TLB; if (isa<InjectedClassNameType>(T)) { InjectedClassNameTypeLoc InjectedTL = TLB.push<InjectedClassNameTypeLoc>(T); InjectedTL.setNameLoc(IdInfo.IdentifierLoc); } else if (isa<RecordType>(T)) { RecordTypeLoc RecordTL = TLB.push<RecordTypeLoc>(T); RecordTL.setNameLoc(IdInfo.IdentifierLoc); } else if (isa<TypedefType>(T)) { TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(T); TypedefTL.setNameLoc(IdInfo.IdentifierLoc); } else if (isa<EnumType>(T)) { EnumTypeLoc EnumTL = TLB.push<EnumTypeLoc>(T); EnumTL.setNameLoc(IdInfo.IdentifierLoc); } else if (isa<TemplateTypeParmType>(T)) { TemplateTypeParmTypeLoc TemplateTypeTL = TLB.push<TemplateTypeParmTypeLoc>(T); TemplateTypeTL.setNameLoc(IdInfo.IdentifierLoc); } else if (isa<UnresolvedUsingType>(T)) { UnresolvedUsingTypeLoc UnresolvedTL = TLB.push<UnresolvedUsingTypeLoc>(T); UnresolvedTL.setNameLoc(IdInfo.IdentifierLoc); } else if (isa<SubstTemplateTypeParmType>(T)) { SubstTemplateTypeParmTypeLoc TL = TLB.push<SubstTemplateTypeParmTypeLoc>(T); TL.setNameLoc(IdInfo.IdentifierLoc); } else if (isa<SubstTemplateTypeParmPackType>(T)) { SubstTemplateTypeParmPackTypeLoc TL = TLB.push<SubstTemplateTypeParmPackTypeLoc>(T); TL.setNameLoc(IdInfo.IdentifierLoc); } else { llvm_unreachable("Unhandled TypeDecl node in nested-name-specifier"); } if (T->isEnumeralType()) Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec); SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T), IdInfo.CCLoc); return false; } // Otherwise, we have an error case. If we don't want diagnostics, just // return an error now. if (ErrorRecoveryLookup) return true; // If we didn't find anything during our lookup, try again with // ordinary name lookup, which can help us produce better error // messages. if (Found.empty()) { Found.clear(LookupOrdinaryName); LookupName(Found, S); } // In Microsoft mode, if we are within a templated function and we can't // resolve Identifier, then extend the SS with Identifier. This will have // the effect of resolving Identifier during template instantiation. // The goal is to be able to resolve a function call whose // nested-name-specifier is located inside a dependent base class. // Example: // // class C { // public: // static void foo2() { } // }; // template <class T> class A { public: typedef C D; }; // // template <class T> class B : public A<T> { // public: // void foo() { D::foo2(); } // }; if (getLangOpts().MSVCCompat) { DeclContext *DC = LookupCtx ? LookupCtx : CurContext; if (DC->isDependentContext() && DC->isFunctionOrMethod()) { CXXRecordDecl *ContainingClass = dyn_cast<CXXRecordDecl>(DC->getParent()); if (ContainingClass && ContainingClass->hasAnyDependentBases()) { Diag(IdInfo.IdentifierLoc, diag::ext_undeclared_unqual_id_with_dependent_base) << IdInfo.Identifier << ContainingClass; SS.Extend(Context, IdInfo.Identifier, IdInfo.IdentifierLoc, IdInfo.CCLoc); return false; } } } if (!Found.empty()) { if (TypeDecl *TD = Found.getAsSingle<TypeDecl>()) Diag(IdInfo.IdentifierLoc, diag::err_expected_class_or_namespace) << Context.getTypeDeclType(TD) << getLangOpts().CPlusPlus; else { Diag(IdInfo.IdentifierLoc, diag::err_expected_class_or_namespace) << IdInfo.Identifier << getLangOpts().CPlusPlus; if (NamedDecl *ND = Found.getAsSingle<NamedDecl>()) Diag(ND->getLocation(), diag::note_entity_declared_at) << IdInfo.Identifier; } } else if (SS.isSet()) Diag(IdInfo.IdentifierLoc, diag::err_no_member) << IdInfo.Identifier << LookupCtx << SS.getRange(); else Diag(IdInfo.IdentifierLoc, diag::err_undeclared_var_use) << IdInfo.Identifier; return true; }
DeclContext::lookup_result DeclContext::lookup(DeclarationName Name) { assert(DeclKind != Decl::LinkageSpec && "Should not perform lookups into linkage specs!"); DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) return PrimaryContext->lookup(Name); #if AXEL_LOOKUP_CHANGES StoredDeclsMap *Map = LookupPtr.getPointer(); if (LookupPtr.getInt()) Map = buildLookup(); #endif if (hasExternalVisibleStorage()) { // If a PCH has a result for this name, and we have a local declaration, we // will have imported the PCH result when adding the local declaration. // FIXME: For modules, we could have had more declarations added by module // imoprts since we saw the declaration of the local name. #if AXEL_LOOKUP_CHANGES if (Map) { #else if (StoredDeclsMap *Map = LookupPtr.getPointer()) { #endif StoredDeclsMap::iterator I = Map->find(Name); if (I != Map->end()) return I->second.getLookupResult(); } ExternalASTSource *Source = getParentASTContext().getExternalSource(); return Source->FindExternalVisibleDeclsByName(this, Name); } #ifndef AXEL_LOOKUP_CHANGES StoredDeclsMap *Map = LookupPtr.getPointer(); if (LookupPtr.getInt()) Map = buildLookup(); #endif if (!Map) return lookup_result(lookup_iterator(0), lookup_iterator(0)); StoredDeclsMap::iterator I = Map->find(Name); if (I == Map->end()) return lookup_result(lookup_iterator(0), lookup_iterator(0)); return I->second.getLookupResult(); } void DeclContext::localUncachedLookup(DeclarationName Name, llvm::SmallVectorImpl<NamedDecl *> &Results) { Results.clear(); // If there's no external storage, just perform a normal lookup and copy // the results. if (!hasExternalVisibleStorage() && !hasExternalLexicalStorage() && Name) { lookup_result LookupResults = lookup(Name); Results.insert(Results.end(), LookupResults.first, LookupResults.second); return; } // If we have a lookup table, check there first. Maybe we'll get lucky. if (Name) { if (StoredDeclsMap *Map = LookupPtr.getPointer()) { StoredDeclsMap::iterator Pos = Map->find(Name); if (Pos != Map->end()) { Results.insert(Results.end(), Pos->second.getLookupResult().first, Pos->second.getLookupResult().second); return; } } } // Slow case: grovel through the declarations in our chain looking for // matches. for (Decl *D = FirstDecl; D; D = D->getNextDeclInContext()) { if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) if (ND->getDeclName() == Name) Results.push_back(ND); } }
/// True if the function should have its body serialized. IsSerialized_t SILDeclRef::isSerialized() const { DeclContext *dc; if (auto closure = getAbstractClosureExpr()) { dc = closure->getLocalContext(); // Otherwise, ask the AST if we're inside an @inlinable context. if (dc->getResilienceExpansion() == ResilienceExpansion::Minimal) { if (isForeign) return IsSerializable; return IsSerialized; } return IsNotSerialized; } if (isIVarInitializerOrDestroyer()) return IsNotSerialized; auto *d = getDecl(); // Default argument generators are serialized if the containing // declaration is public. if (isDefaultArgGenerator()) { ResilienceExpansion expansion; if (auto *EED = dyn_cast<EnumElementDecl>(d)) { expansion = EED->getDefaultArgumentResilienceExpansion(); } else { expansion = cast<AbstractFunctionDecl>(d) ->getDefaultArgumentResilienceExpansion(); } switch (expansion) { case ResilienceExpansion::Minimal: return IsSerialized; case ResilienceExpansion::Maximal: return IsNotSerialized; } } // Stored property initializers are inlinable if the type is explicitly // marked as @_fixed_layout. if (isStoredPropertyInitializer()) { auto *nominal = cast<NominalTypeDecl>(d->getDeclContext()); auto scope = nominal->getFormalAccessScope(/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true); if (!scope.isPublic()) return IsNotSerialized; if (nominal->isFormallyResilient()) return IsNotSerialized; return IsSerialized; } // Note: if 'd' is a function, then 'dc' is the function itself, not // its parent context. dc = d->getInnermostDeclContext(); // Local functions are serializable if their parent function is // serializable. if (d->getDeclContext()->isLocalContext()) { if (dc->getResilienceExpansion() == ResilienceExpansion::Minimal) return IsSerializable; return IsNotSerialized; } // Anything else that is not public is not serializable. if (d->getEffectiveAccess() < AccessLevel::Public) return IsNotSerialized; // 'read' and 'modify' accessors synthesized on-demand are serialized if // visible outside the module. if (auto fn = dyn_cast<FuncDecl>(d)) if (!isClangImported() && fn->hasForcedStaticDispatch()) return IsSerialized; // Enum element constructors are serializable if the enum is // @usableFromInline or public. if (isEnumElement()) return IsSerializable; // Currying thunks are serialized if referenced from an inlinable // context -- Sema's semantic checks ensure the serialization of // such a thunk is valid, since it must in turn reference a public // symbol, or dispatch via class_method or witness_method. if (isCurried) return IsSerializable; if (isForeignToNativeThunk()) return IsSerializable; // The allocating entry point for designated initializers are serialized // if the class is @usableFromInline or public. if (kind == SILDeclRef::Kind::Allocator) { auto *ctor = cast<ConstructorDecl>(d); if (ctor->isDesignatedInit() && ctor->getDeclContext()->getSelfClassDecl()) { if (!ctor->hasClangNode()) return IsSerialized; } } if (isForeign) { // @objc thunks for methods are not serializable since they're only // referenced from the method table. if (d->getDeclContext()->isTypeContext()) return IsNotSerialized; // @objc thunks for top-level functions are serializable since they're // referenced from @convention(c) conversions inside inlinable // functions. return IsSerializable; } // Declarations imported from Clang modules are serialized if // referenced from an inlinable context. if (isClangImported()) return IsSerializable; // Otherwise, ask the AST if we're inside an @inlinable context. if (dc->getResilienceExpansion() == ResilienceExpansion::Minimal) return IsSerialized; return IsNotSerialized; }
bool DeclExtractor::ExtractDecl(FunctionDecl* FD) { llvm::SmallVector<NamedDecl*, 4> TouchedDecls; CompoundStmt* CS = dyn_cast<CompoundStmt>(FD->getBody()); assert(CS && "Function body not a CompoundStmt?"); DeclContext* DC = FD->getTranslationUnitDecl(); Scope* TUScope = m_Sema->TUScope; assert(TUScope == m_Sema->getScopeForContext(DC) && "TU scope from DC?"); llvm::SmallVector<Stmt*, 4> Stmts; for (CompoundStmt::body_iterator I = CS->body_begin(), EI = CS->body_end(); I != EI; ++I) { DeclStmt* DS = dyn_cast<DeclStmt>(*I); if (!DS) { Stmts.push_back(*I); continue; } for (DeclStmt::decl_iterator J = DS->decl_begin(); J != DS->decl_end(); ++J) { NamedDecl* ND = dyn_cast<NamedDecl>(*J); if (isa<UsingDirectiveDecl>(*J)) continue; // FIXME: Here we should be more elegant. if (ND) { if (Stmts.size()) { // We need to emit a new custom wrapper wrapping the stmts EnforceInitOrder(Stmts); assert(!Stmts.size() && "Stmt list must be flushed."); } // We know the transaction is closed, but it is safe. getTransaction()->forceAppend(ND); DeclContext* OldDC = ND->getDeclContext(); // Make sure the decl is not found at its old possition ND->getLexicalDeclContext()->removeDecl(ND); if (Scope* S = m_Sema->getScopeForContext(OldDC)) { S->RemoveDecl(ND); if (utils::Analyze::isOnScopeChains(ND, *m_Sema)) m_Sema->IdResolver.RemoveDecl(ND); } // For variable definitions causing var/function ambiguity such as: // MyClass my();, C++ standard says it shall be resolved as a function // // In the particular context this definition is inside a function // already, but clang thinks it as a lambda, so we need to ignore the // check decl context vs lexical decl context. if (ND->getDeclContext() == ND->getLexicalDeclContext() || isa<FunctionDecl>(ND)) ND->setLexicalDeclContext(DC); else assert(0 && "Not implemented: Decl with different lexical context"); ND->setDeclContext(DC); if (VarDecl* VD = dyn_cast<VarDecl>(ND)) { VD->setStorageClass(SC_None); } clearLinkage(ND); TouchedDecls.push_back(ND); } } } bool hasNoErrors = !CheckForClashingNames(TouchedDecls, DC, TUScope); if (hasNoErrors) { for (size_t i = 0; i < TouchedDecls.size(); ++i) { // We should skip the checks for annonymous decls and we should not // register them in the lookup. if (!TouchedDecls[i]->getDeclName()) continue; m_Sema->PushOnScopeChains(TouchedDecls[i], m_Sema->getScopeForContext(DC), /*AddCurContext*/!isa<UsingDirectiveDecl>(TouchedDecls[i])); // The transparent DeclContexts (eg. scopeless enum) doesn't have // scopes. While extracting their contents we need to update the // lookup tables and telling them to pick up the new possitions // in the AST. if (DeclContext* InnerDC = dyn_cast<DeclContext>(TouchedDecls[i])) { if (InnerDC->isTransparentContext()) { // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*m_Sema, InnerDC); for(DeclContext::decl_iterator DI = InnerDC->decls_begin(), DE = InnerDC->decls_end(); DI != DE ; ++DI) { if (NamedDecl* ND = dyn_cast<NamedDecl>(*DI)) InnerDC->makeDeclVisibleInContext(ND); } } } } } CS->setStmts(*m_Context, Stmts.data(), Stmts.size()); // The order matters, because when we extract decls from the wrapper we // append them to the transaction. If the transaction gets unloaded it will // introduce a fake dependency, so put the move last. Transaction* T = getTransaction(); for (Transaction::iterator I = T->decls_begin(), E = T->decls_end(); I != E; ++I) if (!I->m_DGR.isNull() && I->m_DGR.isSingleDecl() && I->m_DGR.getSingleDecl() == T->getWrapperFD()) { T->erase(I); break; } T->forceAppend(FD); // Put the wrapper after its declarations. (Nice when AST dumping) DC->removeDecl(FD); DC->addDecl(FD); return hasNoErrors; }
ProtocolConformance *ConformanceLookupTable::getConformance( NominalTypeDecl *nominal, LazyResolver *resolver, ConformanceEntry *entry) { // If we already have a conformance, we're done. if (auto conformance = entry->getConformance()) return conformance; ProtocolDecl *protocol = entry->getProtocol(); // Determine where the explicit conformance actually lives. // FIXME: This is a hack to ensure that inherited conformances are // always "single step", which is bad for resilience but is assumed // elsewhere in the compiler. DeclContext *conformingDC = getConformingContext(nominal, resolver, entry); if (!conformingDC) return nullptr; auto *conformingNominal = cast<NominalTypeDecl>(conformingDC-> getAsGenericTypeOrGenericTypeExtensionContext()); // Form the conformance. Type type = entry->getDeclContext()->getDeclaredTypeInContext(); ProtocolConformance *conformance; ASTContext &ctx = nominal->getASTContext(); if (entry->getKind() == ConformanceEntryKind::Inherited) { // For an inherited conformance, the conforming nominal type will // be different from the nominal type. assert(conformingNominal != nominal && "Broken inherited conformance"); // Find the superclass type that matches where the conformance was // declared. Type superclassTy = type->getSuperclass(resolver); while (superclassTy->getAnyNominal() != conformingNominal) superclassTy = superclassTy->getSuperclass(resolver); // Look up the inherited conformance. Module *module = entry->getDeclContext()->getParentModule(); auto inheritedConformance = module->lookupConformance(superclassTy, protocol, resolver) .getPointer(); // Form the inherited conformance. conformance = ctx.getInheritedConformance( type, inheritedConformance->getConcrete()); } else { // Create or find the normal conformance. Type conformingType = conformingDC->getDeclaredTypeInContext(); SourceLoc conformanceLoc = conformingNominal == conformingDC ? conformingNominal->getLoc() : cast<ExtensionDecl>(conformingDC)->getLoc(); conformance = ctx.getConformance(conformingType, protocol, conformanceLoc, conformingDC, ProtocolConformanceState::Incomplete); } // Record the conformance. entry->Conformance = conformance; return conformance; }
void DeclExtractor::EnforceInitOrder(llvm::SmallVectorImpl<Stmt*>& Stmts){ Scope* TUScope = m_Sema->TUScope; DeclContext* TUDC = static_cast<DeclContext*>(TUScope->getEntity()); // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*m_Sema, TUDC); std::string FunctionName = "__fd"; createUniqueName(FunctionName); IdentifierInfo& IIFD = m_Context->Idents.get(FunctionName); SourceLocation Loc; NamedDecl* ND = m_Sema->ImplicitlyDefineFunction(Loc, IIFD, TUScope); if (FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(ND)) { FD->setImplicit(false); // Better for debugging // Add a return statement if it doesn't exist if (!isa<ReturnStmt>(Stmts.back())) { Sema::ContextRAII pushedDC(*m_Sema, FD); // Generate the return statement: // First a literal 0, then the return taking that literal. // One bit is enough: llvm::APInt ZeroInt(m_Context->getIntWidth(m_Context->IntTy), 0, /*isSigned=*/true); IntegerLiteral* ZeroLit = IntegerLiteral::Create(*m_Context, ZeroInt, m_Context->IntTy, SourceLocation()); Stmts.push_back(m_Sema->ActOnReturnStmt(ZeroLit->getExprLoc(), ZeroLit).take()); } // Wrap Stmts into a function body. llvm::ArrayRef<Stmt*> StmtsRef(Stmts.data(), Stmts.size()); CompoundStmt* CS = new (*m_Context)CompoundStmt(*m_Context, StmtsRef, Loc, Loc); FD->setBody(CS); // We know the transaction is closed, but it is safe. getTransaction()->forceAppend(FD); // Create the VarDecl with the init std::string VarName = "__vd"; createUniqueName(VarName); IdentifierInfo& IIVD = m_Context->Idents.get(VarName); VarDecl* VD = VarDecl::Create(*m_Context, TUDC, Loc, Loc, &IIVD, FD->getReturnType(), (TypeSourceInfo*)0, SC_None); LookupResult R(*m_Sema, FD->getDeclName(), Loc, Sema::LookupMemberName); R.addDecl(FD); CXXScopeSpec CSS; Expr* UnresolvedLookup = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).take(); Expr* TheCall = m_Sema->ActOnCallExpr(TUScope, UnresolvedLookup, Loc, MultiExprArg(), Loc).take(); assert(VD && TheCall && "Missing VD or its init!"); VD->setInit(TheCall); // We know the transaction is closed, but it is safe. getTransaction()->forceAppend(VD); // Add it to the transaction for codegenning TUDC->addHiddenDecl(VD); Stmts.clear(); return; } llvm_unreachable("Must be able to enforce init order."); }
bool DeclExtractor::CheckTagDeclaration(TagDecl* NewTD, LookupResult& Previous){ // If the decl is already known invalid, don't check it. if (NewTD->isInvalidDecl()) return false; IdentifierInfo* Name = NewTD->getIdentifier(); // If this is not a definition, it must have a name. assert((Name != 0 || NewTD->isThisDeclarationADefinition()) && "Nameless record must be a definition!"); // Figure out the underlying type if this a enum declaration. We need to do // this early, because it's needed to detect if this is an incompatible // redeclaration. TagDecl::TagKind Kind = NewTD->getTagKind(); bool Invalid = false; assert(NewTD->getNumTemplateParameterLists() == 0 && "Cannot handle that yet!"); bool isExplicitSpecialization = false; if (Kind == TTK_Enum) { EnumDecl* ED = cast<EnumDecl>(NewTD); bool ScopedEnum = ED->isScoped(); const QualType QT = ED->getIntegerType(); if (QT.isNull() && ScopedEnum) // No underlying type explicitly specified, or we failed to parse the // type, default to int. ; //EnumUnderlying = m_Context->IntTy.getTypePtr(); else if (!QT.isNull()) { // C++0x 7.2p2: The type-specifier-seq of an enum-base shall name an // integral type; any cv-qualification is ignored. SourceLocation UnderlyingLoc; TypeSourceInfo* TI = 0; if ((TI = ED->getIntegerTypeSourceInfo())) UnderlyingLoc = TI->getTypeLoc().getBeginLoc(); if (!QT->isDependentType() && !QT->isIntegralType(*m_Context)) { m_Sema->Diag(UnderlyingLoc, diag::err_enum_invalid_underlying) << QT; } if (TI) m_Sema->DiagnoseUnexpandedParameterPack(UnderlyingLoc, TI, Sema::UPPC_FixedUnderlyingType); } } DeclContext *SearchDC = m_Sema->CurContext; DeclContext *DC = m_Sema->CurContext; //bool isStdBadAlloc = false; SourceLocation NameLoc = NewTD->getLocation(); // if (Name && SS.isNotEmpty()) { // // We have a nested-name tag ('struct foo::bar'). // // Check for invalid 'foo::'. // if (SS.isInvalid()) { // Name = 0; // goto CreateNewDecl; // } // // If this is a friend or a reference to a class in a dependent // // context, don't try to make a decl for it. // if (TUK == TUK_Friend || TUK == TUK_Reference) { // DC = computeDeclContext(SS, false); // if (!DC) { // IsDependent = true; // return 0; // } // } else { // DC = computeDeclContext(SS, true); // if (!DC) { // Diag(SS.getRange().getBegin(), // diag::err_dependent_nested_name_spec) // << SS.getRange(); // return 0; // } // } // if (RequireCompleteDeclContext(SS, DC)) // return 0; // SearchDC = DC; // // Look-up name inside 'foo::'. // LookupQualifiedName(Previous, DC); // if (Previous.isAmbiguous()) // return 0; // if (Previous.empty()) { // // Name lookup did not find anything. However, if the // // nested-name-specifier refers to the current instantiation, // // and that current instantiation has any dependent base // // classes, we might find something at instantiation time: treat // // this as a dependent elaborated-type-specifier. // // But this only makes any sense for reference-like lookups. // if (Previous.wasNotFoundInCurrentInstantiation() && // (TUK == TUK_Reference || TUK == TUK_Friend)) { // IsDependent = true; // return 0; // } // // A tag 'foo::bar' must already exist. // Diag(NameLoc, diag::err_not_tag_in_scope) // << Kind << Name << DC << SS.getRange(); // Name = 0; // Invalid = true; // goto CreateNewDecl; // } //} else if (Name) { // If this is a named struct, check to see if there was a previous forward // declaration or definition. // FIXME: We're looking into outer scopes here, even when we // shouldn't be. Doing so can result in ambiguities that we // shouldn't be diagnosing. //LookupName(Previous, S); if (Previous.isAmbiguous()) { LookupResult::Filter F = Previous.makeFilter(); while (F.hasNext()) { NamedDecl *ND = F.next(); if (ND->getDeclContext()->getRedeclContext() != SearchDC) F.erase(); } F.done(); } // Note: there used to be some attempt at recovery here. if (Previous.isAmbiguous()) { return false; } if (!m_Sema->getLangOpts().CPlusPlus) { // FIXME: This makes sure that we ignore the contexts associated // with C structs, unions, and enums when looking for a matching // tag declaration or definition. See the similar lookup tweak // in Sema::LookupName; is there a better way to deal with this? while (isa<RecordDecl>(SearchDC) || isa<EnumDecl>(SearchDC)) SearchDC = SearchDC->getParent(); } } else if (m_Sema->getScopeForContext(m_Sema->CurContext) ->isFunctionPrototypeScope()) { // If this is an enum declaration in function prototype scope, set its // initial context to the translation unit. SearchDC = m_Context->getTranslationUnitDecl(); } if (Previous.isSingleResult() && Previous.getFoundDecl()->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. m_Sema->DiagnoseTemplateParameterShadow(NameLoc, Previous.getFoundDecl()); // Just pretend that we didn't see the previous declaration. Previous.clear(); } if (m_Sema->getLangOpts().CPlusPlus && Name && DC && m_Sema->StdNamespace && DC->Equals(m_Sema->getStdNamespace()) && Name->isStr("bad_alloc")) { // This is a declaration of or a reference to "std::bad_alloc". //isStdBadAlloc = true; if (Previous.empty() && m_Sema->StdBadAlloc) { // std::bad_alloc has been implicitly declared (but made invisible to // name lookup). Fill in this implicit declaration as the previous // declaration, so that the declarations get chained appropriately. Previous.addDecl(m_Sema->getStdBadAlloc()); } } if (!Previous.empty()) { NamedDecl *PrevDecl = (*Previous.begin())->getUnderlyingDecl(); // It's okay to have a tag decl in the same scope as a typedef // which hides a tag decl in the same scope. Finding this // insanity with a redeclaration lookup can only actually happen // in C++. // // This is also okay for elaborated-type-specifiers, which is // technically forbidden by the current standard but which is // okay according to the likely resolution of an open issue; // see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407 if (m_Sema->getLangOpts().CPlusPlus) { if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(PrevDecl)) { if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) { TagDecl *Tag = TT->getDecl(); if (Tag->getDeclName() == Name && Tag->getDeclContext()->getRedeclContext() ->Equals(TD->getDeclContext()->getRedeclContext())) { PrevDecl = Tag; Previous.clear(); Previous.addDecl(Tag); Previous.resolveKind(); } } } } if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) { // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or // rementions the tag), reuse the decl. if (m_Sema->isDeclInScope(PrevDecl, SearchDC, m_Sema->getScopeForContext(m_Sema->CurContext), isExplicitSpecialization)) { // Make sure that this wasn't declared as an enum and now used as a // struct or something similar. SourceLocation KWLoc = NewTD->getLocStart(); if (!m_Sema->isAcceptableTagRedeclaration(PrevTagDecl, Kind, NewTD->isThisDeclarationADefinition(), KWLoc, *Name)) { bool SafeToContinue = (PrevTagDecl->getTagKind() != TTK_Enum && Kind != TTK_Enum); if (SafeToContinue) m_Sema->Diag(KWLoc, diag::err_use_with_wrong_tag) << Name << FixItHint::CreateReplacement(SourceRange(KWLoc), PrevTagDecl->getKindName()); else m_Sema->Diag(KWLoc, diag::err_use_with_wrong_tag) << Name; m_Sema->Diag(PrevTagDecl->getLocation(), diag::note_previous_use); if (SafeToContinue) Kind = PrevTagDecl->getTagKind(); else { // Recover by making this an anonymous redefinition. Name = 0; Previous.clear(); Invalid = true; } } if (Kind == TTK_Enum && PrevTagDecl->getTagKind() == TTK_Enum) { const EnumDecl *NewEnum = cast<EnumDecl>(NewTD); const EnumDecl *PrevEnum = cast<EnumDecl>(PrevTagDecl); // All conflicts with previous declarations are recovered by // returning the previous declaration. if (NewEnum->isScoped() != PrevEnum->isScoped()) { m_Sema->Diag(KWLoc, diag::err_enum_redeclare_scoped_mismatch) << PrevEnum->isScoped(); m_Sema->Diag(PrevTagDecl->getLocation(), diag::note_previous_use); return false; } else if (PrevEnum->isFixed()) { QualType T = NewEnum->getIntegerType(); if (!m_Context->hasSameUnqualifiedType(T, PrevEnum->getIntegerType())) { m_Sema->Diag(NameLoc.isValid() ? NameLoc : KWLoc, diag::err_enum_redeclare_type_mismatch) << T << PrevEnum->getIntegerType(); m_Sema->Diag(PrevTagDecl->getLocation(), diag::note_previous_use); return false; } } else if (NewEnum->isFixed() != PrevEnum->isFixed()) { m_Sema->Diag(KWLoc, diag::err_enum_redeclare_fixed_mismatch) << PrevEnum->isFixed(); m_Sema->Diag(PrevTagDecl->getLocation(), diag::note_previous_use); return false; } } if (!Invalid) { // If this is a use, just return the declaration we found. // Diagnose attempts to redefine a tag. if (NewTD->isThisDeclarationADefinition()) { if (TagDecl* Def = PrevTagDecl->getDefinition()) { // If we're defining a specialization and the previous // definition is from an implicit instantiation, don't emit an // error here; we'll catch this in the general case below. if (!isExplicitSpecialization || !isa<CXXRecordDecl>(Def) || cast<CXXRecordDecl>(Def)->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { m_Sema->Diag(NameLoc, diag::err_redefinition) << Name; m_Sema->Diag(Def->getLocation(), diag::note_previous_definition); // If this is a redefinition, recover by making this // struct be anonymous, which will make any later // references get the previous definition. Name = 0; Previous.clear(); Invalid = true; } } else { // If the type is currently being defined, complain // about a nested redefinition. const TagType *Tag = cast<TagType>(m_Context->getTagDeclType(PrevTagDecl)); if (Tag->isBeingDefined()) { m_Sema->Diag(NameLoc, diag::err_nested_redefinition) << Name; m_Sema->Diag(PrevTagDecl->getLocation(), diag::note_previous_definition); Name = 0; Previous.clear(); Invalid = true; } } // Okay, this is definition of a previously declared or referenced // tag PrevDecl. We're going to create a new Decl for it. } } // If we get here we have (another) forward declaration or we // have a definition. Just create a new decl. } else { // If we get here, this is a definition of a new tag type in a nested // scope, e.g. "struct foo; void bar() { struct foo; }", just create a // new decl/type. We set PrevDecl to NULL so that the entities // have distinct types. Previous.clear(); } // If we get here, we're going to create a new Decl. If PrevDecl // is non-NULL, it's a definition of the tag declared by // PrevDecl. If it's NULL, we have a new definition. // Otherwise, PrevDecl is not a tag, but was found with tag // lookup. This is only actually possible in C++, where a few // things like templates still live in the tag namespace. } else { assert(m_Sema->getLangOpts().CPlusPlus); // Diagnose if the declaration is in scope. if (!m_Sema->isDeclInScope(PrevDecl, SearchDC, m_Sema->getScopeForContext(m_Sema->CurContext), isExplicitSpecialization)) { // do nothing // Otherwise it's a declaration. Call out a particularly common // case here. } else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(PrevDecl)) { unsigned Kind = 0; if (isa<TypeAliasDecl>(PrevDecl)) Kind = 1; m_Sema->Diag(NameLoc, diag::err_tag_definition_of_typedef) << Name << Kind << TND->getUnderlyingType(); m_Sema->Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl; Invalid = true; // Otherwise, diagnose. } else { // The tag name clashes with something else in the target scope, // issue an error and recover by making this tag be anonymous. m_Sema->Diag(NameLoc, diag::err_redefinition_different_kind) << Name; m_Sema->Diag(PrevDecl->getLocation(), diag::note_previous_definition); Name = 0; Invalid = true; } // The existing declaration isn't relevant to us; we're in a // new scope, so clear out the previous declaration. Previous.clear(); } } if (Invalid) { return false; } return true; }
/// \brief Build a new nested-name-specifier for "identifier::", as described /// by ActOnCXXNestedNameSpecifier. /// /// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in /// that it contains an extra parameter \p ScopeLookupResult, which provides /// the result of name lookup within the scope of the nested-name-specifier /// that was computed at template definition time. /// /// If ErrorRecoveryLookup is true, then this call is used to improve error /// recovery. This means that it should not emit diagnostics, it should /// just return true on failure. It also means it should only return a valid /// scope if it *knows* that the result is correct. It should not return in a /// dependent context, for example. Nor will it extend \p SS with the scope /// specifier. bool Sema::BuildCXXNestedNameSpecifier(Scope *S, IdentifierInfo &Identifier, SourceLocation IdentifierLoc, SourceLocation CCLoc, QualType ObjectType, bool EnteringContext, CXXScopeSpec &SS, NamedDecl *ScopeLookupResult, bool ErrorRecoveryLookup) { LookupResult Found(*this, &Identifier, IdentifierLoc, LookupNestedNameSpecifierName); // Determine where to perform name lookup DeclContext *LookupCtx = 0; bool isDependent = false; if (!ObjectType.isNull()) { // This nested-name-specifier occurs in a member access expression, e.g., // x->B::f, and we are looking into the type of the object. assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); isDependent = ObjectType->isDependentType(); } else if (SS.isSet()) { // This nested-name-specifier occurs after another nested-name-specifier, // so look into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = isDependentScopeSpecifier(SS); Found.setContextRange(SS.getRange()); } bool ObjectTypeSearchedInScope = false; if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we // computed, which is either the type of the base of a member access // expression or the declaration context associated with a prior // nested-name-specifier. // The declaration context must be complete. if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS, LookupCtx)) return true; LookupQualifiedName(Found, LookupCtx); if (!ObjectType.isNull() && Found.empty()) { // C++ [basic.lookup.classref]p4: // If the id-expression in a class member access is a qualified-id of // the form // // class-name-or-namespace-name::... // // the class-name-or-namespace-name following the . or -> operator is // looked up both in the context of the entire postfix-expression and in // the scope of the class of the object expression. If the name is found // only in the scope of the class of the object expression, the name // shall refer to a class-name. If the name is found only in the // context of the entire postfix-expression, the name shall refer to a // class-name or namespace-name. [...] // // Qualified name lookup into a class will not find a namespace-name, // so we do not need to diagnose that case specifically. However, // this qualified name lookup may find nothing. In that case, perform // unqualified name lookup in the given scope (if available) or // reconstruct the result from when name lookup was performed at template // definition time. if (S) LookupName(Found, S); else if (ScopeLookupResult) Found.addDecl(ScopeLookupResult); ObjectTypeSearchedInScope = true; } } else if (!isDependent) { // Perform unqualified name lookup in the current scope. LookupName(Found, S); } // If we performed lookup into a dependent context and did not find anything, // that's fine: just build a dependent nested-name-specifier. if (Found.empty() && isDependent && !(LookupCtx && LookupCtx->isRecord() && (!cast<CXXRecordDecl>(LookupCtx)->hasDefinition() || !cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()))) { // Don't speculate if we're just trying to improve error recovery. if (ErrorRecoveryLookup) return true; // We were not able to compute the declaration context for a dependent // base object type or prior nested-name-specifier, so this // nested-name-specifier refers to an unknown specialization. Just build // a dependent nested-name-specifier. SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc); return false; } // FIXME: Deal with ambiguities cleanly. if (Found.empty() && !ErrorRecoveryLookup) { // We haven't found anything, and we're not recovering from a // different kind of error, so look for typos. DeclarationName Name = Found.getLookupName(); TypoCorrection Corrected; Found.clear(); if ((Corrected = CorrectTypo(Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS, LookupCtx, EnteringContext, CTC_NoKeywords)) && isAcceptableNestedNameSpecifier(Corrected.getCorrectionDecl())) { std::string CorrectedStr(Corrected.getAsString(getLangOptions())); std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions())); if (LookupCtx) Diag(Found.getNameLoc(), diag::err_no_member_suggest) << Name << LookupCtx << CorrectedQuotedStr << SS.getRange() << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr); else Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest) << Name << CorrectedQuotedStr << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr); if (NamedDecl *ND = Corrected.getCorrectionDecl()) { Diag(ND->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr; Found.addDecl(ND); } Found.setLookupName(Corrected.getCorrection()); } else { Found.setLookupName(&Identifier); } } NamedDecl *SD = Found.getAsSingle<NamedDecl>(); if (isAcceptableNestedNameSpecifier(SD)) { if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) { // C++ [basic.lookup.classref]p4: // [...] If the name is found in both contexts, the // class-name-or-namespace-name shall refer to the same entity. // // We already found the name in the scope of the object. Now, look // into the current scope (the scope of the postfix-expression) to // see if we can find the same name there. As above, if there is no // scope, reconstruct the result from the template instantiation itself. NamedDecl *OuterDecl; if (S) { LookupResult FoundOuter(*this, &Identifier, IdentifierLoc, LookupNestedNameSpecifierName); LookupName(FoundOuter, S); OuterDecl = FoundOuter.getAsSingle<NamedDecl>(); } else OuterDecl = ScopeLookupResult; if (isAcceptableNestedNameSpecifier(OuterDecl) && OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() && (!isa<TypeDecl>(OuterDecl) || !isa<TypeDecl>(SD) || !Context.hasSameType( Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)), Context.getTypeDeclType(cast<TypeDecl>(SD))))) { if (ErrorRecoveryLookup) return true; Diag(IdentifierLoc, diag::err_nested_name_member_ref_lookup_ambiguous) << &Identifier; Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type) << ObjectType; Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope); // Fall through so that we'll pick the name we found in the object // type, since that's probably what the user wanted anyway. } } // If we're just performing this lookup for error-recovery purposes, // don't extend the nested-name-specifier. Just return now. if (ErrorRecoveryLookup) return false; if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD)) { SS.Extend(Context, Namespace, IdentifierLoc, CCLoc); return false; } if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD)) { SS.Extend(Context, Alias, IdentifierLoc, CCLoc); return false; } QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD)); TypeLocBuilder TLB; if (isa<InjectedClassNameType>(T)) { InjectedClassNameTypeLoc InjectedTL = TLB.push<InjectedClassNameTypeLoc>(T); InjectedTL.setNameLoc(IdentifierLoc); } else if (isa<RecordType>(T)) { RecordTypeLoc RecordTL = TLB.push<RecordTypeLoc>(T); RecordTL.setNameLoc(IdentifierLoc); } else if (isa<TypedefType>(T)) { TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(T); TypedefTL.setNameLoc(IdentifierLoc); } else if (isa<EnumType>(T)) { EnumTypeLoc EnumTL = TLB.push<EnumTypeLoc>(T); EnumTL.setNameLoc(IdentifierLoc); } else if (isa<TemplateTypeParmType>(T)) { TemplateTypeParmTypeLoc TemplateTypeTL = TLB.push<TemplateTypeParmTypeLoc>(T); TemplateTypeTL.setNameLoc(IdentifierLoc); } else if (isa<UnresolvedUsingType>(T)) { UnresolvedUsingTypeLoc UnresolvedTL = TLB.push<UnresolvedUsingTypeLoc>(T); UnresolvedTL.setNameLoc(IdentifierLoc); } else if (isa<SubstTemplateTypeParmType>(T)) { SubstTemplateTypeParmTypeLoc TL = TLB.push<SubstTemplateTypeParmTypeLoc>(T); TL.setNameLoc(IdentifierLoc); } else if (isa<SubstTemplateTypeParmPackType>(T)) { SubstTemplateTypeParmPackTypeLoc TL = TLB.push<SubstTemplateTypeParmPackTypeLoc>(T); TL.setNameLoc(IdentifierLoc); } else { llvm_unreachable("Unhandled TypeDecl node in nested-name-specifier"); } if (T->isEnumeralType()) Diag(IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec); SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T), CCLoc); return false; } // Otherwise, we have an error case. If we don't want diagnostics, just // return an error now. if (ErrorRecoveryLookup) return true; // If we didn't find anything during our lookup, try again with // ordinary name lookup, which can help us produce better error // messages. if (Found.empty()) { Found.clear(LookupOrdinaryName); LookupName(Found, S); } // In Microsoft mode, if we are within a templated function and we can't // resolve Identifier, then extend the SS with Identifier. This will have // the effect of resolving Identifier during template instantiation. // The goal is to be able to resolve a function call whose // nested-name-specifier is located inside a dependent base class. // Example: // // class C { // public: // static void foo2() { } // }; // template <class T> class A { public: typedef C D; }; // // template <class T> class B : public A<T> { // public: // void foo() { D::foo2(); } // }; if (getLangOptions().MicrosoftExt) { DeclContext *DC = LookupCtx ? LookupCtx : CurContext; if (DC->isDependentContext() && DC->isFunctionOrMethod()) { SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc); return false; } } unsigned DiagID; if (!Found.empty()) DiagID = diag::err_expected_class_or_namespace; else if (SS.isSet()) { Diag(IdentifierLoc, diag::err_no_member) << &Identifier << LookupCtx << SS.getRange(); return true; } else DiagID = diag::err_undeclared_var_use; if (SS.isSet()) Diag(IdentifierLoc, DiagID) << &Identifier << SS.getRange(); else Diag(IdentifierLoc, DiagID) << &Identifier; return true; }
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"); }
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."); }
/// \brief Build a new nested-name-specifier for "identifier::", as described /// by ActOnCXXNestedNameSpecifier. /// /// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in /// that it contains an extra parameter \p ScopeLookupResult, which provides /// the result of name lookup within the scope of the nested-name-specifier /// that was computed at template definition time. /// /// If ErrorRecoveryLookup is true, then this call is used to improve error /// recovery. This means that it should not emit diagnostics, it should /// just return null on failure. It also means it should only return a valid /// scope if it *knows* that the result is correct. It should not return in a /// dependent context, for example. Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, QualType ObjectType, NamedDecl *ScopeLookupResult, bool EnteringContext, bool ErrorRecoveryLookup) { NestedNameSpecifier *Prefix = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName); // Determine where to perform name lookup DeclContext *LookupCtx = 0; bool isDependent = false; if (!ObjectType.isNull()) { // This nested-name-specifier occurs in a member access expression, e.g., // x->B::f, and we are looking into the type of the object. assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); isDependent = ObjectType->isDependentType(); } else if (SS.isSet()) { // This nested-name-specifier occurs after another nested-name-specifier, // so long into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = isDependentScopeSpecifier(SS); Found.setContextRange(SS.getRange()); } bool ObjectTypeSearchedInScope = false; if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we // computed, which is either the type of the base of a member access // expression or the declaration context associated with a prior // nested-name-specifier. // The declaration context must be complete. if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) return 0; LookupQualifiedName(Found, LookupCtx); if (!ObjectType.isNull() && Found.empty()) { // C++ [basic.lookup.classref]p4: // If the id-expression in a class member access is a qualified-id of // the form // // class-name-or-namespace-name::... // // the class-name-or-namespace-name following the . or -> operator is // looked up both in the context of the entire postfix-expression and in // the scope of the class of the object expression. If the name is found // only in the scope of the class of the object expression, the name // shall refer to a class-name. If the name is found only in the // context of the entire postfix-expression, the name shall refer to a // class-name or namespace-name. [...] // // Qualified name lookup into a class will not find a namespace-name, // so we do not need to diagnoste that case specifically. However, // this qualified name lookup may find nothing. In that case, perform // unqualified name lookup in the given scope (if available) or // reconstruct the result from when name lookup was performed at template // definition time. if (S) LookupName(Found, S); else if (ScopeLookupResult) Found.addDecl(ScopeLookupResult); ObjectTypeSearchedInScope = true; } } else if (isDependent) { // Don't speculate if we're just trying to improve error recovery. if (ErrorRecoveryLookup) return 0; // We were not able to compute the declaration context for a dependent // base object type or prior nested-name-specifier, so this // nested-name-specifier refers to an unknown specialization. Just build // a dependent nested-name-specifier. if (!Prefix) return NestedNameSpecifier::Create(Context, &II); return NestedNameSpecifier::Create(Context, Prefix, &II); } else { // Perform unqualified name lookup in the current scope. LookupName(Found, S); } // FIXME: Deal with ambiguities cleanly. if (Found.empty() && !ErrorRecoveryLookup) { // We haven't found anything, and we're not recovering from a // different kind of error, so look for typos. DeclarationName Name = Found.getLookupName(); if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext) && Found.isSingleResult() && isAcceptableNestedNameSpecifier(Found.getAsSingle<NamedDecl>())) { if (LookupCtx) Diag(Found.getNameLoc(), diag::err_no_member_suggest) << Name << LookupCtx << Found.getLookupName() << SS.getRange() << CodeModificationHint::CreateReplacement(Found.getNameLoc(), Found.getLookupName().getAsString()); else Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest) << Name << Found.getLookupName() << CodeModificationHint::CreateReplacement(Found.getNameLoc(), Found.getLookupName().getAsString()); if (NamedDecl *ND = Found.getAsSingle<NamedDecl>()) Diag(ND->getLocation(), diag::note_previous_decl) << ND->getDeclName(); } else Found.clear(); } NamedDecl *SD = Found.getAsSingle<NamedDecl>(); if (isAcceptableNestedNameSpecifier(SD)) { if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) { // C++ [basic.lookup.classref]p4: // [...] If the name is found in both contexts, the // class-name-or-namespace-name shall refer to the same entity. // // We already found the name in the scope of the object. Now, look // into the current scope (the scope of the postfix-expression) to // see if we can find the same name there. As above, if there is no // scope, reconstruct the result from the template instantiation itself. NamedDecl *OuterDecl; if (S) { LookupResult FoundOuter(*this, &II, IdLoc, LookupNestedNameSpecifierName); LookupName(FoundOuter, S); OuterDecl = FoundOuter.getAsSingle<NamedDecl>(); } else OuterDecl = ScopeLookupResult; if (isAcceptableNestedNameSpecifier(OuterDecl) && OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() && (!isa<TypeDecl>(OuterDecl) || !isa<TypeDecl>(SD) || !Context.hasSameType( Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)), Context.getTypeDeclType(cast<TypeDecl>(SD))))) { if (ErrorRecoveryLookup) return 0; Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous) << &II; Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type) << ObjectType; Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope); // Fall through so that we'll pick the name we found in the object // type, since that's probably what the user wanted anyway. } } if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD)) return NestedNameSpecifier::Create(Context, Prefix, Namespace); // FIXME: It would be nice to maintain the namespace alias name, then // see through that alias when resolving the nested-name-specifier down to // a declaration context. if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD)) return NestedNameSpecifier::Create(Context, Prefix, Alias->getNamespace()); QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD)); return NestedNameSpecifier::Create(Context, Prefix, false, T.getTypePtr()); } // Otherwise, we have an error case. If we don't want diagnostics, just // return an error now. if (ErrorRecoveryLookup) return 0; // If we didn't find anything during our lookup, try again with // ordinary name lookup, which can help us produce better error // messages. if (Found.empty()) { Found.clear(LookupOrdinaryName); LookupName(Found, S); } unsigned DiagID; if (!Found.empty()) DiagID = diag::err_expected_class_or_namespace; else if (SS.isSet()) { Diag(IdLoc, diag::err_no_member) << &II << LookupCtx << SS.getRange(); return 0; } else DiagID = diag::err_undeclared_var_use; if (SS.isSet()) Diag(IdLoc, DiagID) << &II << SS.getRange(); else Diag(IdLoc, DiagID) << &II; return 0; }
void SILGenFunction::emitMemberInitializers(DeclContext *dc, VarDecl *selfDecl, NominalTypeDecl *nominal) { for (auto member : nominal->getMembers()) { // Find instance pattern binding declarations that have initializers. if (auto pbd = dyn_cast<PatternBindingDecl>(member)) { if (pbd->isStatic()) continue; for (auto entry : pbd->getPatternList()) { auto init = entry.getInit(); if (!init) continue; // Cleanup after this initialization. FullExpr scope(Cleanups, entry.getPattern()); // Get the substitutions for the constructor context. SubstitutionList subs; auto *genericEnv = dc->getGenericEnvironmentOfContext(); DeclContext *typeDC = dc; while (!typeDC->isTypeContext()) typeDC = typeDC->getParent(); auto typeGenericSig = typeDC->getGenericSignatureOfContext(); if (genericEnv && typeGenericSig) { // Generate a set of substitutions for the initialization function, // whose generic signature is that of the type context, and whose // replacement types are the archetypes of the initializer itself. SmallVector<Substitution, 4> subsVec; typeGenericSig->getSubstitutions( [&](SubstitutableType *type) { if (auto gp = type->getAs<GenericTypeParamType>()) { return genericEnv->mapTypeIntoContext(gp); } return Type(type); }, [](CanType dependentType, Type conformingReplacementType, ProtocolType *conformedProtocol) { return ProtocolConformanceRef( conformedProtocol->getDecl()); }, subsVec); subs = SGM.getASTContext().AllocateCopy(subsVec); } // Get the type of the initialization result, in terms // of the constructor context's archetypes. CanType resultType = getInitializationTypeInContext( pbd->getDeclContext(), dc, entry.getPattern())->getCanonicalType(); AbstractionPattern origResultType(resultType); // FIXME: Can emitMemberInit() share code with // InitializationForPattern in SILGenDecl.cpp? RValue result = emitApplyOfStoredPropertyInitializer( init, entry, subs, resultType, origResultType, SGFContext()); emitMemberInit(*this, selfDecl, entry.getPattern(), std::move(result)); } } // Introduce behavior initialization markers for properties that need them. if (auto var = dyn_cast<VarDecl>(member)) { if (var->isStatic()) continue; if (!var->hasBehaviorNeedingInitialization()) continue; // Get the initializer method for behavior. auto init = var->getBehavior()->InitStorageDecl; SILValue initFn = getBehaviorInitStorageFn(*this, var); // Get the behavior's storage we need to initialize. auto storage = var->getBehavior()->StorageDecl; LValue storageRef = emitLValueForMemberInit(*this, var, selfDecl,storage); // Shed any reabstraction over the member. while (storageRef.isLastComponentTranslation()) storageRef.dropLastTranslationComponent(); auto storageAddr = emitAddressOfLValue(var, std::move(storageRef), AccessKind::ReadWrite); // Get the setter. auto setterFn = getBehaviorSetterFn(*this, var); auto self = emitSelfForMemberInit(*this, var, selfDecl); auto mark = B.createMarkUninitializedBehavior(var, initFn, init.getSubstitutions(), storageAddr.getValue(), setterFn, getForwardingSubstitutions(), self.getValue(), getLoweredType(var->getType()).getAddressType()); // The mark instruction stands in for the behavior property. VarLocs[var].value = mark; } } }
/// Do a syntactic pattern match to determine whether the call is a call /// to swap(&base[index1], &base[index2]), which can /// be replaced with a call to MutableCollection.swapAt(_:_:) on base. /// /// Returns true if the call can be replaced. Returns the call expression, /// the base expression, and the two indices as out expressions. /// /// This method takes an array of all the ApplyInsts for calls to swap() /// in the function to avoid needing to construct a parent map over the AST /// to find the CallExpr for the inout accesses. static bool canReplaceWithCallToCollectionSwapAt(const BeginAccessInst *Access1, const BeginAccessInst *Access2, ArrayRef<ApplyInst *> CallsToSwap, ASTContext &Ctx, CallExpr *&FoundCall, Expr *&Base, Expr *&Index1, Expr *&Index2) { if (CallsToSwap.empty()) return false; // Inout arguments must be modifications. if (Access1->getAccessKind() != SILAccessKind::Modify || Access2->getAccessKind() != SILAccessKind::Modify) { return false; } SILLocation Loc1 = Access1->getLoc(); SILLocation Loc2 = Access2->getLoc(); if (Loc1.isNull() || Loc2.isNull()) return false; auto *InOut1 = Loc1.getAsASTNode<InOutExpr>(); auto *InOut2 = Loc2.getAsASTNode<InOutExpr>(); if (!InOut1 || !InOut2) return false; FoundCall = nullptr; // Look through all the calls to swap() recorded in the function to find // which one we're diagnosing. for (ApplyInst *AI : CallsToSwap) { SILLocation CallLoc = AI->getLoc(); if (CallLoc.isNull()) continue; auto *CE = CallLoc.getAsASTNode<CallExpr>(); if (!CE) continue; assert(isCallToStandardLibrarySwap(CE, Ctx)); // swap() takes two arguments. auto *ArgTuple = cast<TupleExpr>(CE->getArg()); const Expr *Arg1 = ArgTuple->getElement(0); const Expr *Arg2 = ArgTuple->getElement(1); if ((Arg1 == InOut1 && Arg2 == InOut2)) { FoundCall = CE; break; } } if (!FoundCall) return false; // We found a call to swap(&e1, &e2). Now check to see whether it // matches the form swap(&someCollection[index1], &someCollection[index2]). auto *SE1 = dyn_cast<SubscriptExpr>(InOut1->getSubExpr()); if (!SE1) return false; auto *SE2 = dyn_cast<SubscriptExpr>(InOut2->getSubExpr()); if (!SE2) return false; // Do the two subscripts refer to the same subscript declaration? auto *Decl1 = cast<SubscriptDecl>(SE1->getDecl().getDecl()); auto *Decl2 = cast<SubscriptDecl>(SE2->getDecl().getDecl()); if (Decl1 != Decl2) return false; ProtocolDecl *MutableCollectionDecl = Ctx.getMutableCollectionDecl(); // Is the subcript either (1) on MutableCollection itself or (2) a // a witness for a subscript on MutableCollection? bool IsSubscriptOnMutableCollection = false; ProtocolDecl *ProtocolForDecl = Decl1->getDeclContext()->getSelfProtocolDecl(); if (ProtocolForDecl) { IsSubscriptOnMutableCollection = (ProtocolForDecl == MutableCollectionDecl); } else { for (ValueDecl *Req : Decl1->getSatisfiedProtocolRequirements()) { DeclContext *ReqDC = Req->getDeclContext(); ProtocolDecl *ReqProto = ReqDC->getSelfProtocolDecl(); assert(ReqProto && "Protocol requirement not in a protocol?"); if (ReqProto == MutableCollectionDecl) { IsSubscriptOnMutableCollection = true; break; } } } if (!IsSubscriptOnMutableCollection) return false; // We're swapping two subscripts on mutable collections -- but are they // the same collection? Approximate this by checking for textual // equality on the base expressions. This is just an approximation, // but is fine for a best-effort Fix-It. SourceManager &SM = Ctx.SourceMgr; StringRef Base1Text = extractExprText(SE1->getBase(), SM); StringRef Base2Text = extractExprText(SE2->getBase(), SM); if (Base1Text != Base2Text) return false; auto *Index1Paren = dyn_cast<ParenExpr>(SE1->getIndex()); if (!Index1Paren) return false; auto *Index2Paren = dyn_cast<ParenExpr>(SE2->getIndex()); if (!Index2Paren) return false; Base = SE1->getBase(); Index1 = Index1Paren->getSubExpr(); Index2 = Index2Paren->getSubExpr(); return true; }
/// \brief True if the function should have its body serialized. IsSerialized_t SILDeclRef::isSerialized() const { DeclContext *dc; if (auto closure = getAbstractClosureExpr()) dc = closure->getLocalContext(); else { auto *d = getDecl(); // Default argument generators are serialized if the function was // type-checked in Swift 4 mode. if (kind == SILDeclRef::Kind::DefaultArgGenerator) { auto *afd = cast<AbstractFunctionDecl>(d); switch (afd->getDefaultArgumentResilienceExpansion()) { case ResilienceExpansion::Minimal: return IsSerialized; case ResilienceExpansion::Maximal: return IsNotSerialized; } } // 'read' and 'modify' accessors synthesized on-demand are serialized if // visible outside the module. if (auto fn = dyn_cast<FuncDecl>(d)) if (!isClangImported() && fn->hasForcedStaticDispatch() && fn->getEffectiveAccess() >= AccessLevel::Public) return IsSerialized; dc = getDecl()->getInnermostDeclContext(); // Enum element constructors are serialized if the enum is // @usableFromInline or public. if (isEnumElement()) if (d->getEffectiveAccess() >= AccessLevel::Public) return IsSerialized; // Currying thunks are serialized if referenced from an inlinable // context -- Sema's semantic checks ensure the serialization of // such a thunk is valid, since it must in turn reference a public // symbol, or dispatch via class_method or witness_method. if (isCurried) if (d->getEffectiveAccess() >= AccessLevel::Public) return IsSerializable; if (isForeignToNativeThunk()) return IsSerializable; // The allocating entry point for designated initializers are serialized // if the class is @usableFromInline or public. if (kind == SILDeclRef::Kind::Allocator) { auto *ctor = cast<ConstructorDecl>(d); if (ctor->isDesignatedInit() && ctor->getDeclContext()->getSelfClassDecl()) { if (ctor->getEffectiveAccess() >= AccessLevel::Public && !ctor->hasClangNode()) return IsSerialized; } } // Stored property initializers are inlinable if the type is explicitly // marked as @_fixed_layout. if (isStoredPropertyInitializer()) { auto *nominal = cast<NominalTypeDecl>(d->getDeclContext()); auto scope = nominal->getFormalAccessScope(/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true); if (!scope.isPublic()) return IsNotSerialized; if (nominal->isFormallyResilient()) return IsNotSerialized; return IsSerialized; } } // Declarations imported from Clang modules are serialized if // referenced from an inlinable context. if (isClangImported()) return IsSerializable; // Otherwise, ask the AST if we're inside an @inlinable context. if (dc->getResilienceExpansion() == ResilienceExpansion::Minimal) return IsSerialized; return IsNotSerialized; }
bool ValuePrinterSynthesizer::tryAttachVP(FunctionDecl* FD) { // We have to be able to mark the expression for printout. There are // three scenarios: // 0: Expression printing disabled - don't do anything just exit. // 1: Expression printing enabled - print no matter what. // 2: Expression printing auto - analyze - rely on the omitted ';' to // not produce the suppress marker. int indexOfLastExpr = -1; Expr* To = utils::Analyze::GetOrCreateLastExpr(FD, &indexOfLastExpr, /*omitDS*/false, m_Sema); if (To) { // Update the CompoundStmt body, avoiding alloc/dealloc of all the el. CompoundStmt* CS = cast<CompoundStmt>(FD->getBody()); assert(CS && "Missing body?"); switch (getCompilationOpts().ValuePrinting) { case CompilationOptions::VPDisabled: assert(0 && "Don't wait that long. Exit early!"); break; case CompilationOptions::VPEnabled: break; case CompilationOptions::VPAuto: { // FIXME: Propagate the flag to the nested transactions also, they // must have the same CO as their parents. getCompilationOpts().ValuePrinting = CompilationOptions::VPEnabled; if ((int)CS->size() > indexOfLastExpr+1 && (*(CS->body_begin() + indexOfLastExpr + 1)) && isa<NullStmt>(*(CS->body_begin() + indexOfLastExpr + 1))) { // If next is NullStmt disable VP is disabled - exit. Signal this in // the CO of the transaction. getCompilationOpts().ValuePrinting = CompilationOptions::VPDisabled; } if (getCompilationOpts().ValuePrinting == CompilationOptions::VPDisabled) return true; } break; } // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*m_Sema, FD); if (To) { // Strip the parenthesis if any if (ParenExpr* PE = dyn_cast<ParenExpr>(To)) To = PE->getSubExpr(); Expr* Result = 0; // if (!m_Sema->getLangOpts().CPlusPlus) // Result = SynthesizeVP(To); if (Result) *(CS->body_begin()+indexOfLastExpr) = Result; } // Clear the artificial NullStmt-s if (!ClearNullStmts(CS)) { // FIXME: Why it is here? Shouldn't it be in DeclExtractor? // if no body remove the wrapper DeclContext* DC = FD->getDeclContext(); Scope* S = m_Sema->getScopeForContext(DC); if (S) S->RemoveDecl(FD); DC->removeDecl(FD); } } else // if nothing to attach to set the CO's ValuePrinting to disabled. getCompilationOpts().ValuePrinting = CompilationOptions::VPDisabled; return true; }
/// Check the generic parameters in the given generic parameter list (and its /// parent generic parameter lists) according to the given resolver. bool TypeChecker::checkGenericParamList(ArchetypeBuilder *builder, GenericParamList *genericParams, GenericSignature *parentSig, bool adoptArchetypes, GenericTypeResolver *resolver) { bool invalid = false; // If there is a parent context, add the generic parameters and requirements // from that context. if (builder) builder->addGenericSignature(parentSig, adoptArchetypes); // If there aren't any generic parameters at this level, we're done. if (!genericParams) return false; assert(genericParams->size() > 0 && "Parsed an empty generic parameter list?"); // Determine where and how to perform name lookup for the generic // parameter lists and where clause. TypeResolutionOptions options; DeclContext *lookupDC = genericParams->begin()[0]->getDeclContext(); if (!lookupDC->isModuleScopeContext()) { assert(isa<GenericTypeDecl>(lookupDC) || isa<ExtensionDecl>(lookupDC) || isa<AbstractFunctionDecl>(lookupDC) && "not a proper generic parameter context?"); options = TR_GenericSignature; } // First, set the depth of each generic parameter, and add them to the // archetype builder. Do this before checking the inheritance clause, // since it may itself be dependent on one of these parameters. unsigned depth = genericParams->getDepth(); for (auto param : *genericParams) { param->setDepth(depth); if (builder) { if (builder->addGenericParameter(param)) invalid = true; } } // Now, check the inheritance clauses of each parameter. for (auto param : *genericParams) { checkInheritanceClause(param, resolver); if (builder) { builder->addGenericParameterRequirements(param); // Infer requirements from the inherited types. for (const auto &inherited : param->getInherited()) { if (builder->inferRequirements(inherited, genericParams)) invalid = true; } } } // Visit each of the requirements, adding them to the builder. // Add the requirements clause to the builder, validating the types in // the requirements clause along the way. for (auto &req : genericParams->getRequirements()) { if (req.isInvalid()) continue; switch (req.getKind()) { case RequirementReprKind::TypeConstraint: { // Validate the types. if (validateType(req.getSubjectLoc(), lookupDC, options, resolver)) { invalid = true; req.setInvalid(); continue; } if (validateType(req.getConstraintLoc(), lookupDC, options, resolver)) { invalid = true; req.setInvalid(); continue; } // FIXME: Feels too early to perform this check. if (!req.getConstraint()->isExistentialType() && !req.getConstraint()->getClassOrBoundGenericClass()) { diagnose(genericParams->getWhereLoc(), diag::requires_conformance_nonprotocol, req.getSubjectLoc(), req.getConstraintLoc()); req.getConstraintLoc().setInvalidType(Context); invalid = true; req.setInvalid(); continue; } break; } case RequirementReprKind::SameType: if (validateType(req.getFirstTypeLoc(), lookupDC, options, resolver)) { invalid = true; req.setInvalid(); continue; } if (validateType(req.getSecondTypeLoc(), lookupDC, options, resolver)) { invalid = true; req.setInvalid(); continue; } break; } if (builder && builder->addRequirement(req)) { invalid = true; req.setInvalid(); } } return invalid; }