diff options
Diffstat (limited to 'lib/Sema/SemaLookup.cpp')
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 268 |
1 files changed, 169 insertions, 99 deletions
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index effccc2f3d..2b7924d244 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1,9 +1,8 @@ //===--------------------- SemaLookup.cpp - Name Lookup ------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -279,6 +278,10 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, IDNS = Decl::IDNS_OMPReduction; break; + case Sema::LookupOMPMapperName: + IDNS = Decl::IDNS_OMPMapper; + break; + case Sema::LookupAnyName: IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol @@ -1540,8 +1543,21 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { // and in C we must not because each declaration of a function gets its own // set of declarations for tags in prototype scope. bool VisibleWithinParent; - if (D->isTemplateParameter() || isa<ParmVarDecl>(D) || - (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus)) + if (D->isTemplateParameter()) { + bool SearchDefinitions = true; + if (const auto *DCD = dyn_cast<Decl>(DC)) { + if (const auto *TD = DCD->getDescribedTemplate()) { + TemplateParameterList *TPL = TD->getTemplateParameters(); + auto Index = getDepthAndIndex(D).second; + SearchDefinitions = Index >= TPL->size() || TPL->getParam(Index) != D; + } + } + if (SearchDefinitions) + VisibleWithinParent = SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC)); + else + VisibleWithinParent = isVisible(SemaRef, cast<NamedDecl>(DC)); + } else if (isa<ParmVarDecl>(D) || + (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus)) VisibleWithinParent = isVisible(SemaRef, cast<NamedDecl>(DC)); else if (D->isModulePrivate()) { // A module-private declaration is only visible if an enclosing lexical @@ -2104,6 +2120,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, BaseCallback = &CXXRecordDecl::FindOMPReductionMember; break; + case LookupOMPMapperName: + BaseCallback = &CXXRecordDecl::FindOMPMapperMember; + break; + case LookupUsingDeclName: // This lookup is for redeclarations only. @@ -2165,11 +2185,27 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, DeclContext::lookup_iterator FirstD = FirstPath->Decls.begin(); DeclContext::lookup_iterator CurrentD = Path->Decls.begin(); + // Get the decl that we should use for deduplicating this lookup. + auto GetRepresentativeDecl = [&](NamedDecl *D) -> Decl * { + // C++ [temp.local]p3: + // A lookup that finds an injected-class-name (10.2) can result in + // an ambiguity in certain cases (for example, if it is found in + // more than one base class). If all of the injected-class-names + // that are found refer to specializations of the same class + // template, and if the name is used as a template-name, the + // reference refers to the class template itself and not a + // specialization thereof, and is not ambiguous. + if (R.isTemplateNameLookup()) + if (auto *TD = getAsTemplateNameDecl(D)) + D = TD; + return D->getUnderlyingDecl()->getCanonicalDecl(); + }; + while (FirstD != FirstPath->Decls.end() && CurrentD != Path->Decls.end()) { - if ((*FirstD)->getUnderlyingDecl()->getCanonicalDecl() != - (*CurrentD)->getUnderlyingDecl()->getCanonicalDecl()) - break; + if (GetRepresentativeDecl(*FirstD) != + GetRepresentativeDecl(*CurrentD)) + break; ++FirstD; ++CurrentD; @@ -2417,40 +2453,56 @@ namespace { InstantiationLoc(InstantiationLoc) { } + bool addClassTransitive(CXXRecordDecl *RD) { + Classes.insert(RD); + return ClassesTransitive.insert(RD); + } + Sema &S; Sema::AssociatedNamespaceSet &Namespaces; Sema::AssociatedClassSet &Classes; SourceLocation InstantiationLoc; + + private: + Sema::AssociatedClassSet ClassesTransitive; }; } // end anonymous namespace static void addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType T); +// Given the declaration context \param Ctx of a class, class template or +// enumeration, add the associated namespaces to \param Namespaces as described +// in [basic.lookup.argdep]p2. static void CollectEnclosingNamespace(Sema::AssociatedNamespaceSet &Namespaces, DeclContext *Ctx) { - // Add the associated namespace for this class. - - // We don't use DeclContext::getEnclosingNamespaceContext() as this may - // be a locally scoped record. + // The exact wording has been changed in C++14 as a result of + // CWG 1691 (see also CWG 1690 and CWG 1692). We apply it unconditionally + // to all language versions since it is possible to return a local type + // from a lambda in C++11. + // + // C++14 [basic.lookup.argdep]p2: + // If T is a class type [...]. Its associated namespaces are the innermost + // enclosing namespaces of its associated classes. [...] + // + // If T is an enumeration type, its associated namespace is the innermost + // enclosing namespace of its declaration. [...] - // We skip out of inline namespaces. The innermost non-inline namespace + // We additionally skip inline namespaces. The innermost non-inline namespace // contains all names of all its nested inline namespaces anyway, so we can // replace the entire inline namespace tree with its root. - while (Ctx->isRecord() || Ctx->isTransparentContext() || - Ctx->isInlineNamespace()) + while (!Ctx->isFileContext() || Ctx->isInlineNamespace()) Ctx = Ctx->getParent(); - if (Ctx->isFileContext()) - Namespaces.insert(Ctx->getPrimaryContext()); + Namespaces.insert(Ctx->getPrimaryContext()); } // Add the associated classes and namespaces for argument-dependent -// lookup that involves a template argument (C++ [basic.lookup.koenig]p2). +// lookup that involves a template argument (C++ [basic.lookup.argdep]p2). static void addAssociatedClassesAndNamespaces(AssociatedLookup &Result, const TemplateArgument &Arg) { - // C++ [basic.lookup.koenig]p2, last bullet: + // C++ [basic.lookup.argdep]p2, last bullet: // -- [...] ; switch (Arg.getKind()) { case TemplateArgument::Null: @@ -2495,9 +2547,8 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, } } -// Add the associated classes and namespaces for -// argument-dependent lookup with an argument of class type -// (C++ [basic.lookup.koenig]p2). +// Add the associated classes and namespaces for argument-dependent lookup +// with an argument of class type (C++ [basic.lookup.argdep]p2). static void addAssociatedClassesAndNamespaces(AssociatedLookup &Result, CXXRecordDecl *Class) { @@ -2506,30 +2557,22 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, if (Class->getDeclName() == Result.S.VAListTagName) return; - // C++ [basic.lookup.koenig]p2: + // C++ [basic.lookup.argdep]p2: // [...] // -- If T is a class type (including unions), its associated // classes are: the class itself; the class of which it is a - // member, if any; and its direct and indirect base - // classes. Its associated namespaces are the namespaces in - // which its associated classes are defined. + // member, if any; and its direct and indirect base classes. + // Its associated namespaces are the innermost enclosing + // namespaces of its associated classes. // Add the class of which it is a member, if any. DeclContext *Ctx = Class->getDeclContext(); if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) Result.Classes.insert(EnclosingClass); + // Add the associated namespace for this class. CollectEnclosingNamespace(Result.Namespaces, Ctx); - // Add the class itself. If we've already seen this class, we don't - // need to visit base classes. - // - // FIXME: That's not correct, we may have added this class only because it - // was the enclosing class of another class, and in that case we won't have - // added its base classes yet. - if (!Result.Classes.insert(Class)) - return; - // -- If T is a template-id, its associated namespaces and classes are // the namespace in which the template is defined; for member // templates, the member template's class; the namespaces and classes @@ -2552,6 +2595,11 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, addAssociatedClassesAndNamespaces(Result, TemplateArgs[I]); } + // Add the class itself. If we've already transitively visited this class, + // we don't need to visit base classes. + if (!Result.addClassTransitive(Class)) + return; + // Only recurse into base classes for complete types. if (!Result.S.isCompleteType(Result.InstantiationLoc, Result.S.Context.getRecordType(Class))) @@ -2577,7 +2625,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, if (!BaseType) continue; CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - if (Result.Classes.insert(BaseDecl)) { + if (Result.addClassTransitive(BaseDecl)) { // Find the associated namespace for this base class. DeclContext *BaseCtx = BaseDecl->getDeclContext(); CollectEnclosingNamespace(Result.Namespaces, BaseCtx); @@ -2642,10 +2690,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { break; // -- If T is a class type (including unions), its associated - // classes are: the class itself; the class of which it is a - // member, if any; and its direct and indirect base - // classes. Its associated namespaces are the namespaces in - // which its associated classes are defined. + // classes are: the class itself; the class of which it is + // a member, if any; and its direct and indirect base classes. + // Its associated namespaces are the innermost enclosing + // namespaces of its associated classes. case Type::Record: { CXXRecordDecl *Class = cast<CXXRecordDecl>(cast<RecordType>(T)->getDecl()); @@ -2653,10 +2701,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { break; } - // -- If T is an enumeration type, its associated namespace is - // the namespace in which it is defined. If it is class - // member, its associated class is the member's class; else - // it has no associated class. + // -- If T is an enumeration type, its associated namespace + // is the innermost enclosing namespace of its declaration. + // If it is a class member, its associated class is the + // member’s class; else it has no associated class. case Type::Enum: { EnumDecl *Enum = cast<EnumType>(T)->getDecl(); @@ -2664,7 +2712,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) Result.Classes.insert(EnclosingClass); - // Add the associated namespace for this class. + // Add the associated namespace for this enumeration. CollectEnclosingNamespace(Result.Namespaces, Ctx); break; @@ -2793,15 +2841,9 @@ void Sema::FindAssociatedClassesAndNamespaces( // in which the function or function template is defined and the // classes and namespaces associated with its (non-dependent) // parameter types and return type. - Arg = Arg->IgnoreParens(); - if (UnaryOperator *unaryOp = dyn_cast<UnaryOperator>(Arg)) - if (unaryOp->getOpcode() == UO_AddrOf) - Arg = unaryOp->getSubExpr(); + OverloadExpr *OE = OverloadExpr::find(Arg).Expression; - UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Arg); - if (!ULE) continue; - - for (const auto *D : ULE->decls()) { + for (const NamedDecl *D : OE->decls()) { // Look through any using declarations to find the underlying function. const FunctionDecl *FDecl = D->getUnderlyingDecl()->getAsFunction(); @@ -4317,9 +4359,8 @@ void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier( SpecifierOStream.flush(); SameNameSpecifier = NewNameSpecifier == CurNameSpecifier; } - if (SameNameSpecifier || - std::find(CurContextIdentifiers.begin(), CurContextIdentifiers.end(), - Name) != CurContextIdentifiers.end()) { + if (SameNameSpecifier || llvm::find(CurContextIdentifiers, Name) != + CurContextIdentifiers.end()) { // Rebuild the NestedNameSpecifier as a globally-qualified specifier. NNS = NestedNameSpecifier::GlobalSpecifier(Context); NumSpecifiers = @@ -4551,8 +4592,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef, std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer( const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, - Scope *S, CXXScopeSpec *SS, - std::unique_ptr<CorrectionCandidateCallback> CCC, + Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT, bool ErrorRecovery) { @@ -4614,9 +4654,13 @@ std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer( TypoName.getBeginLoc()); } - CorrectionCandidateCallback &CCCRef = *CCC; + // Extend the lifetime of the callback. We delayed this until here + // to avoid allocations in the hot path (which is where no typo correction + // occurs). Note that CorrectionCandidateCallback is polymorphic and + // initially stack-allocated. + std::unique_ptr<CorrectionCandidateCallback> ClonedCCC = CCC.clone(); auto Consumer = llvm::make_unique<TypoCorrectionConsumer>( - *this, TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, + *this, TypoName, LookupKind, S, SS, std::move(ClonedCCC), MemberContext, EnteringContext); // Perform name lookup to find visible, similarly-named entities. @@ -4668,7 +4712,9 @@ std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer( } } - AddKeywordsToConsumer(*this, *Consumer, S, CCCRef, SS && SS->isNotEmpty()); + AddKeywordsToConsumer(*this, *Consumer, S, + *Consumer->getCorrectionValidator(), + SS && SS->isNotEmpty()); // Build the NestedNameSpecifiers for the KnownNamespaces, if we're going // to search those namespaces. @@ -4722,19 +4768,18 @@ std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer( TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, - std::unique_ptr<CorrectionCandidateCallback> CCC, + CorrectionCandidateCallback &CCC, CorrectTypoKind Mode, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT, bool RecordFailure) { - assert(CCC && "CorrectTypo requires a CorrectionCandidateCallback"); - // Always let the ExternalSource have the first chance at correction, even // if we would otherwise have given up. if (ExternalSource) { - if (TypoCorrection Correction = ExternalSource->CorrectTypo( - TypoName, LookupKind, S, SS, *CCC, MemberContext, EnteringContext, OPT)) + if (TypoCorrection Correction = + ExternalSource->CorrectTypo(TypoName, LookupKind, S, SS, CCC, + MemberContext, EnteringContext, OPT)) return Correction; } @@ -4742,12 +4787,12 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, // WantObjCSuper is only true for CTC_ObjCMessageReceiver and for // some instances of CTC_Unknown, while WantRemainingKeywords is true // for CTC_Unknown but not for CTC_ObjCMessageReceiver. - bool ObjCMessageReceiver = CCC->WantObjCSuper && !CCC->WantRemainingKeywords; + bool ObjCMessageReceiver = CCC.WantObjCSuper && !CCC.WantRemainingKeywords; IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); - auto Consumer = makeTypoCorrectionConsumer( - TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, - EnteringContext, OPT, Mode == CTK_ErrorRecovery); + auto Consumer = makeTypoCorrectionConsumer(TypoName, LookupKind, S, SS, CCC, + MemberContext, EnteringContext, + OPT, Mode == CTK_ErrorRecovery); if (!Consumer) return TypoCorrection(); @@ -4857,16 +4902,13 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, /// needed. TypoExpr *Sema::CorrectTypoDelayed( const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, - Scope *S, CXXScopeSpec *SS, - std::unique_ptr<CorrectionCandidateCallback> CCC, + Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC, TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC, CorrectTypoKind Mode, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT) { - assert(CCC && "CorrectTypoDelayed requires a CorrectionCandidateCallback"); - - auto Consumer = makeTypoCorrectionConsumer( - TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, - EnteringContext, OPT, Mode == CTK_ErrorRecovery); + auto Consumer = makeTypoCorrectionConsumer(TypoName, LookupKind, S, SS, CCC, + MemberContext, EnteringContext, + OPT, Mode == CTK_ErrorRecovery); // Give the external sema source a chance to correct the typo. TypoCorrection ExternalTypo; @@ -5052,7 +5094,7 @@ void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, auto Merged = Context.getModulesWithMergedDefinition(Def); OwningModules.insert(OwningModules.end(), Merged.begin(), Merged.end()); - diagnoseMissingImport(Loc, Decl, Decl->getLocation(), OwningModules, MIK, + diagnoseMissingImport(Loc, Def, Def->getLocation(), OwningModules, MIK, Recover); } @@ -5072,12 +5114,58 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, MissingImportKind MIK, bool Recover) { assert(!Modules.empty()); + auto NotePrevious = [&] { + unsigned DiagID; + switch (MIK) { + case MissingImportKind::Declaration: + DiagID = diag::note_previous_declaration; + break; + case MissingImportKind::Definition: + DiagID = diag::note_previous_definition; + break; + case MissingImportKind::DefaultArgument: + DiagID = diag::note_default_argument_declared_here; + break; + case MissingImportKind::ExplicitSpecialization: + DiagID = diag::note_explicit_specialization_declared_here; + break; + case MissingImportKind::PartialSpecialization: + DiagID = diag::note_partial_specialization_declared_here; + break; + } + Diag(DeclLoc, DiagID); + }; + // Weed out duplicates from module list. llvm::SmallVector<Module*, 8> UniqueModules; llvm::SmallDenseSet<Module*, 8> UniqueModuleSet; - for (auto *M : Modules) + for (auto *M : Modules) { + if (M->Kind == Module::GlobalModuleFragment) + continue; if (UniqueModuleSet.insert(M).second) UniqueModules.push_back(M); + } + + if (UniqueModules.empty()) { + // All candidates were global module fragments. Try to suggest a #include. + const FileEntry *E = + PP.getModuleHeaderToIncludeForDiagnostics(UseLoc, Modules[0], DeclLoc); + // FIXME: Find a smart place to suggest inserting a #include, and add + // a FixItHint there. + Diag(UseLoc, diag::err_module_unimported_use_global_module_fragment) + << (int)MIK << Decl << !!E + << (E ? getIncludeStringForHeader(PP, E) : ""); + // Produce a "previous" note if it will point to a header rather than some + // random global module fragment. + // FIXME: Suppress the note backtrace even under + // -fdiagnostics-show-note-include-stack. + if (E) + NotePrevious(); + if (Recover) + createImplicitModuleImportForErrorRecovery(UseLoc, Modules[0]); + return; + } + Modules = UniqueModules; if (Modules.size() > 1) { @@ -5110,25 +5198,7 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, << (int)MIK << Decl << Modules[0]->getFullModuleName(); } - unsigned DiagID; - switch (MIK) { - case MissingImportKind::Declaration: - DiagID = diag::note_previous_declaration; - break; - case MissingImportKind::Definition: - DiagID = diag::note_previous_definition; - break; - case MissingImportKind::DefaultArgument: - DiagID = diag::note_default_argument_declared_here; - break; - case MissingImportKind::ExplicitSpecialization: - DiagID = diag::note_explicit_specialization_declared_here; - break; - case MissingImportKind::PartialSpecialization: - DiagID = diag::note_partial_specialization_declared_here; - break; - } - Diag(DeclLoc, DiagID); + NotePrevious(); // Try to recover by implicitly importing this module. if (Recover) |