diff options
Diffstat (limited to 'lib/Sema/SemaLookup.cpp')
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 853 |
1 files changed, 488 insertions, 365 deletions
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 8a24dd884a76..d56c5980237c 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -673,82 +673,160 @@ LLVM_DUMP_METHOD void LookupResult::dump() { D->dump(); } -/// When trying to resolve a function name, if the isOpenCLBuiltin function -/// defined in "OpenCLBuiltins.inc" returns a non-null <Index, Len>, then the -/// identifier is referencing an OpenCL builtin function. Thus, all its -/// prototypes are added to the LookUpResult. +/// Get the QualType instances of the return type and arguments for an OpenCL +/// builtin function signature. +/// \param Context (in) The Context instance. +/// \param OpenCLBuiltin (in) The signature currently handled. +/// \param GenTypeMaxCnt (out) Maximum number of types contained in a generic +/// type used as return type or as argument. +/// Only meaningful for generic types, otherwise equals 1. +/// \param RetTypes (out) List of the possible return types. +/// \param ArgTypes (out) List of the possible argument types. For each +/// argument, ArgTypes contains QualTypes for the Cartesian product +/// of (vector sizes) x (types) . +static void GetQualTypesForOpenCLBuiltin( + ASTContext &Context, const OpenCLBuiltinStruct &OpenCLBuiltin, + unsigned &GenTypeMaxCnt, SmallVector<QualType, 1> &RetTypes, + SmallVector<SmallVector<QualType, 1>, 5> &ArgTypes) { + // Get the QualType instances of the return types. + unsigned Sig = SignatureTable[OpenCLBuiltin.SigTableIndex]; + OCL2Qual(Context, TypeTable[Sig], RetTypes); + GenTypeMaxCnt = RetTypes.size(); + + // Get the QualType instances of the arguments. + // First type is the return type, skip it. + for (unsigned Index = 1; Index < OpenCLBuiltin.NumTypes; Index++) { + SmallVector<QualType, 1> Ty; + OCL2Qual(Context, + TypeTable[SignatureTable[OpenCLBuiltin.SigTableIndex + Index]], Ty); + GenTypeMaxCnt = (Ty.size() > GenTypeMaxCnt) ? Ty.size() : GenTypeMaxCnt; + ArgTypes.push_back(std::move(Ty)); + } +} + +/// Create a list of the candidate function overloads for an OpenCL builtin +/// function. +/// \param Context (in) The ASTContext instance. +/// \param GenTypeMaxCnt (in) Maximum number of types contained in a generic +/// type used as return type or as argument. +/// Only meaningful for generic types, otherwise equals 1. +/// \param FunctionList (out) List of FunctionTypes. +/// \param RetTypes (in) List of the possible return types. +/// \param ArgTypes (in) List of the possible types for the arguments. +static void GetOpenCLBuiltinFctOverloads( + ASTContext &Context, unsigned GenTypeMaxCnt, + std::vector<QualType> &FunctionList, SmallVector<QualType, 1> &RetTypes, + SmallVector<SmallVector<QualType, 1>, 5> &ArgTypes) { + FunctionProtoType::ExtProtoInfo PI; + PI.Variadic = false; + + // Create FunctionTypes for each (gen)type. + for (unsigned IGenType = 0; IGenType < GenTypeMaxCnt; IGenType++) { + SmallVector<QualType, 5> ArgList; + + for (unsigned A = 0; A < ArgTypes.size(); A++) { + // Builtins such as "max" have an "sgentype" argument that represents + // the corresponding scalar type of a gentype. The number of gentypes + // must be a multiple of the number of sgentypes. + assert(GenTypeMaxCnt % ArgTypes[A].size() == 0 && + "argument type count not compatible with gentype type count"); + unsigned Idx = IGenType % ArgTypes[A].size(); + ArgList.push_back(ArgTypes[A][Idx]); + } + + FunctionList.push_back(Context.getFunctionType( + RetTypes[(RetTypes.size() != 1) ? IGenType : 0], ArgList, PI)); + } +} + +/// When trying to resolve a function name, if isOpenCLBuiltin() returns a +/// non-null <Index, Len> pair, then the name is referencing an OpenCL +/// builtin function. Add all candidate signatures to the LookUpResult. /// -/// \param S The Sema instance -/// \param LR The LookupResult instance -/// \param II The identifier being resolved -/// \param Index The list of prototypes starts at Index in OpenCLBuiltins[] -/// \param Len The list of prototypes has Len elements -static void InsertOCLBuiltinDeclarations(Sema &S, LookupResult &LR, - IdentifierInfo *II, unsigned Index, - unsigned Len) { - - for (unsigned i = 0; i < Len; ++i) { - const OpenCLBuiltinDecl &Decl = OpenCLBuiltins[Index - 1 + i]; +/// \param S (in) The Sema instance. +/// \param LR (inout) The LookupResult instance. +/// \param II (in) The identifier being resolved. +/// \param FctIndex (in) Starting index in the BuiltinTable. +/// \param Len (in) The signature list has Len elements. +static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR, + IdentifierInfo *II, + const unsigned FctIndex, + const unsigned Len) { + // The builtin function declaration uses generic types (gentype). + bool HasGenType = false; + + // Maximum number of types contained in a generic type used as return type or + // as argument. Only meaningful for generic types, otherwise equals 1. + unsigned GenTypeMaxCnt; + + for (unsigned SignatureIndex = 0; SignatureIndex < Len; SignatureIndex++) { + const OpenCLBuiltinStruct &OpenCLBuiltin = + BuiltinTable[FctIndex + SignatureIndex]; ASTContext &Context = S.Context; - // Ignore this BIF if the version is incorrect. - if (Context.getLangOpts().OpenCLVersion < Decl.Version) + // Ignore this BIF if its version does not match the language options. + if (Context.getLangOpts().OpenCLVersion < OpenCLBuiltin.MinVersion) + continue; + if ((OpenCLBuiltin.MaxVersion != 0) && + (Context.getLangOpts().OpenCLVersion >= OpenCLBuiltin.MaxVersion)) continue; - FunctionProtoType::ExtProtoInfo PI; - PI.Variadic = false; - - // Defined in "OpenCLBuiltins.inc" - QualType RT = OCL2Qual(Context, OpenCLSignature[Decl.ArgTableIndex]); + SmallVector<QualType, 1> RetTypes; + SmallVector<SmallVector<QualType, 1>, 5> ArgTypes; - SmallVector<QualType, 5> ArgTypes; - for (unsigned I = 1; I < Decl.NumArgs; I++) { - QualType Ty = OCL2Qual(Context, OpenCLSignature[Decl.ArgTableIndex + I]); - ArgTypes.push_back(Ty); + // Obtain QualType lists for the function signature. + GetQualTypesForOpenCLBuiltin(Context, OpenCLBuiltin, GenTypeMaxCnt, + RetTypes, ArgTypes); + if (GenTypeMaxCnt > 1) { + HasGenType = true; } - QualType R = Context.getFunctionType(RT, ArgTypes, PI); - SourceLocation Loc = LR.getNameLoc(); + // Create function overload for each type combination. + std::vector<QualType> FunctionList; + GetOpenCLBuiltinFctOverloads(Context, GenTypeMaxCnt, FunctionList, RetTypes, + ArgTypes); - // TODO: This part is taken from Sema::LazilyCreateBuiltin, - // maybe refactor it. + SourceLocation Loc = LR.getNameLoc(); DeclContext *Parent = Context.getTranslationUnitDecl(); - FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, R, - /*TInfo=*/nullptr, SC_Extern, - false, R->isFunctionProtoType()); - New->setImplicit(); - - // Create Decl objects for each parameter, adding them to the - // FunctionDecl. - if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) { - SmallVector<ParmVarDecl *, 16> Params; - for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) { - ParmVarDecl *Parm = - ParmVarDecl::Create(Context, New, SourceLocation(), - SourceLocation(), nullptr, FT->getParamType(i), - /*TInfo=*/nullptr, SC_None, nullptr); - Parm->setScopeInfo(0, i); - Params.push_back(Parm); + FunctionDecl *NewOpenCLBuiltin; + + for (unsigned Index = 0; Index < GenTypeMaxCnt; Index++) { + NewOpenCLBuiltin = FunctionDecl::Create( + Context, Parent, Loc, Loc, II, FunctionList[Index], + /*TInfo=*/nullptr, SC_Extern, false, + FunctionList[Index]->isFunctionProtoType()); + NewOpenCLBuiltin->setImplicit(); + + // Create Decl objects for each parameter, adding them to the + // FunctionDecl. + if (const FunctionProtoType *FP = + dyn_cast<FunctionProtoType>(FunctionList[Index])) { + SmallVector<ParmVarDecl *, 16> ParmList; + for (unsigned IParm = 0, e = FP->getNumParams(); IParm != e; ++IParm) { + ParmVarDecl *Parm = ParmVarDecl::Create( + Context, NewOpenCLBuiltin, SourceLocation(), SourceLocation(), + nullptr, FP->getParamType(IParm), + /*TInfo=*/nullptr, SC_None, nullptr); + Parm->setScopeInfo(0, IParm); + ParmList.push_back(Parm); + } + NewOpenCLBuiltin->setParams(ParmList); } - New->setParams(Params); + if (!S.getLangOpts().OpenCLCPlusPlus) { + NewOpenCLBuiltin->addAttr(OverloadableAttr::CreateImplicit(Context)); + } + LR.addDecl(NewOpenCLBuiltin); } - - New->addAttr(OverloadableAttr::CreateImplicit(Context)); - - if (strlen(Decl.Extension)) - S.setOpenCLExtensionForDecl(New, Decl.Extension); - - LR.addDecl(New); } // If we added overloads, need to resolve the lookup result. - if (Len > 1) + if (Len > 1 || HasGenType) LR.resolveKind(); } /// Lookup a builtin function, when name lookup would otherwise /// fail. -static bool LookupBuiltin(Sema &S, LookupResult &R) { +bool Sema::LookupBuiltin(LookupResult &R) { Sema::LookupNameKind NameKind = R.getLookupKind(); // If we didn't find a use of this identifier, and if the identifier @@ -758,21 +836,22 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) { NameKind == Sema::LookupRedeclarationWithLinkage) { IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo(); if (II) { - if (S.getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) { - if (II == S.getASTContext().getMakeIntegerSeqName()) { - R.addDecl(S.getASTContext().getMakeIntegerSeqDecl()); + if (getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) { + if (II == getASTContext().getMakeIntegerSeqName()) { + R.addDecl(getASTContext().getMakeIntegerSeqDecl()); return true; - } else if (II == S.getASTContext().getTypePackElementName()) { - R.addDecl(S.getASTContext().getTypePackElementDecl()); + } else if (II == getASTContext().getTypePackElementName()) { + R.addDecl(getASTContext().getTypePackElementDecl()); return true; } } // Check if this is an OpenCL Builtin, and if so, insert its overloads. - if (S.getLangOpts().OpenCL && S.getLangOpts().DeclareOpenCLBuiltins) { + if (getLangOpts().OpenCL && getLangOpts().DeclareOpenCLBuiltins) { auto Index = isOpenCLBuiltin(II->getName()); if (Index.first) { - InsertOCLBuiltinDeclarations(S, R, II, Index.first, Index.second); + InsertOCLBuiltinDeclarationsFromTable(*this, R, II, Index.first - 1, + Index.second); return true; } } @@ -781,14 +860,14 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) { if (unsigned BuiltinID = II->getBuiltinID()) { // In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined // library functions like 'malloc'. Instead, we'll just error. - if ((S.getLangOpts().CPlusPlus || S.getLangOpts().OpenCL) && - S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) + if ((getLangOpts().CPlusPlus || getLangOpts().OpenCL) && + Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) return false; - if (NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II, - BuiltinID, S.TUScope, - R.isForRedeclaration(), - R.getNameLoc())) { + if (NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, + BuiltinID, TUScope, + R.isForRedeclaration(), + R.getNameLoc())) { R.addDecl(D); return true; } @@ -934,7 +1013,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { } } - if (!Found && DC->isTranslationUnit() && LookupBuiltin(S, R)) + if (!Found && DC->isTranslationUnit() && S.LookupBuiltin(R)) return true; if (R.getLookupName().getNameKind() @@ -1932,7 +2011,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { // If we didn't find a use of this identifier, and if the identifier // corresponds to a compiler builtin, create the decl object for the builtin // now, injecting it into translation unit scope, and return it. - if (AllowBuiltinCreation && LookupBuiltin(*this, R)) + if (AllowBuiltinCreation && LookupBuiltin(R)) return true; // If we didn't find a use of this identifier, the ExternalSource @@ -2051,7 +2130,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, /// Callback that looks for any member of a class with the given name. static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, DeclarationName Name) { - RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + RecordDecl *BaseRecord = Specifier->getType()->castAs<RecordType>()->getDecl(); Path.Decls = BaseRecord->lookup(Name); return !Path.Decls.empty(); @@ -2750,7 +2829,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { #define NON_CANONICAL_TYPE(Class, Base) case Type::Class: #define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: #define ABSTRACT_TYPE(Class, Base) -#include "clang/AST/TypeNodes.def" +#include "clang/AST/TypeNodes.inc" // T is canonical. We can also ignore dependent types because // we don't need to do ADL at the definition point, but if we // wanted to implement template export (or if we find some other @@ -3016,8 +3095,11 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, SpecialMemberCache.InsertNode(Result, InsertPoint); if (SM == CXXDestructor) { - if (RD->needsImplicitDestructor()) - DeclareImplicitDestructor(RD); + if (RD->needsImplicitDestructor()) { + runWithSufficientStackSpace(RD->getLocation(), [&] { + DeclareImplicitDestructor(RD); + }); + } CXXDestructorDecl *DD = RD->getDestructor(); assert(DD && "record without a destructor"); Result->setMethod(DD); @@ -3040,21 +3122,36 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, if (SM == CXXDefaultConstructor) { Name = Context.DeclarationNames.getCXXConstructorName(CanTy); NumArgs = 0; - if (RD->needsImplicitDefaultConstructor()) - DeclareImplicitDefaultConstructor(RD); + if (RD->needsImplicitDefaultConstructor()) { + runWithSufficientStackSpace(RD->getLocation(), [&] { + DeclareImplicitDefaultConstructor(RD); + }); + } } else { if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) { Name = Context.DeclarationNames.getCXXConstructorName(CanTy); - if (RD->needsImplicitCopyConstructor()) - DeclareImplicitCopyConstructor(RD); - if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor()) - DeclareImplicitMoveConstructor(RD); + if (RD->needsImplicitCopyConstructor()) { + runWithSufficientStackSpace(RD->getLocation(), [&] { + DeclareImplicitCopyConstructor(RD); + }); + } + if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor()) { + runWithSufficientStackSpace(RD->getLocation(), [&] { + DeclareImplicitMoveConstructor(RD); + }); + } } else { Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); - if (RD->needsImplicitCopyAssignment()) - DeclareImplicitCopyAssignment(RD); - if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment()) - DeclareImplicitMoveAssignment(RD); + if (RD->needsImplicitCopyAssignment()) { + runWithSufficientStackSpace(RD->getLocation(), [&] { + DeclareImplicitCopyAssignment(RD); + }); + } + if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment()) { + runWithSufficientStackSpace(RD->getLocation(), [&] { + DeclareImplicitMoveAssignment(RD); + }); + } } if (ConstArg) @@ -3211,12 +3308,14 @@ CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class, DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { // If the implicit constructors have not yet been declared, do so now. if (CanDeclareSpecialMemberFunction(Class)) { - if (Class->needsImplicitDefaultConstructor()) - DeclareImplicitDefaultConstructor(Class); - if (Class->needsImplicitCopyConstructor()) - DeclareImplicitCopyConstructor(Class); - if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor()) - DeclareImplicitMoveConstructor(Class); + runWithSufficientStackSpace(Class->getLocation(), [&] { + if (Class->needsImplicitDefaultConstructor()) + DeclareImplicitDefaultConstructor(Class); + if (Class->needsImplicitCopyConstructor()) + DeclareImplicitCopyConstructor(Class); + if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor()) + DeclareImplicitMoveConstructor(Class); + }); } CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class)); @@ -3609,328 +3708,347 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { return nullptr; } -static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, - bool QualifiedNameLookup, - bool InBaseClass, - VisibleDeclConsumer &Consumer, - VisibleDeclsRecord &Visited, - bool IncludeDependentBases, - bool LoadExternal) { - if (!Ctx) - return; - - // Make sure we don't visit the same context twice. - if (Visited.visitedContext(Ctx->getPrimaryContext())) - return; - - Consumer.EnteredContext(Ctx); - - // Outside C++, lookup results for the TU live on identifiers. - if (isa<TranslationUnitDecl>(Ctx) && - !Result.getSema().getLangOpts().CPlusPlus) { - auto &S = Result.getSema(); - auto &Idents = S.Context.Idents; - - // Ensure all external identifiers are in the identifier table. - if (LoadExternal) - if (IdentifierInfoLookup *External = Idents.getExternalIdentifierLookup()) { - std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers()); - for (StringRef Name = Iter->Next(); !Name.empty(); Name = Iter->Next()) - Idents.get(Name); - } +namespace { +class LookupVisibleHelper { +public: + LookupVisibleHelper(VisibleDeclConsumer &Consumer, bool IncludeDependentBases, + bool LoadExternal) + : Consumer(Consumer), IncludeDependentBases(IncludeDependentBases), + LoadExternal(LoadExternal) {} + + void lookupVisibleDecls(Sema &SemaRef, Scope *S, Sema::LookupNameKind Kind, + bool IncludeGlobalScope) { + // Determine the set of using directives available during + // unqualified name lookup. + Scope *Initial = S; + UnqualUsingDirectiveSet UDirs(SemaRef); + if (SemaRef.getLangOpts().CPlusPlus) { + // Find the first namespace or translation-unit scope. + while (S && !isNamespaceOrTranslationUnitScope(S)) + S = S->getParent(); - // Walk all lookup results in the TU for each identifier. - for (const auto &Ident : Idents) { - for (auto I = S.IdResolver.begin(Ident.getValue()), - E = S.IdResolver.end(); - I != E; ++I) { - if (S.IdResolver.isDeclInScope(*I, Ctx)) { - if (NamedDecl *ND = Result.getAcceptableDecl(*I)) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); - Visited.add(ND); - } - } - } + UDirs.visitScopeChain(Initial, S); } + UDirs.done(); - return; + // Look for visible declarations. + LookupResult Result(SemaRef, DeclarationName(), SourceLocation(), Kind); + Result.setAllowHidden(Consumer.includeHiddenDecls()); + if (!IncludeGlobalScope) + Visited.visitedContext(SemaRef.getASTContext().getTranslationUnitDecl()); + ShadowContextRAII Shadow(Visited); + lookupInScope(Initial, Result, UDirs); } - if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) - Result.getSema().ForceDeclarationOfImplicitMembers(Class); + void lookupVisibleDecls(Sema &SemaRef, DeclContext *Ctx, + Sema::LookupNameKind Kind, bool IncludeGlobalScope) { + LookupResult Result(SemaRef, DeclarationName(), SourceLocation(), Kind); + Result.setAllowHidden(Consumer.includeHiddenDecls()); + if (!IncludeGlobalScope) + Visited.visitedContext(SemaRef.getASTContext().getTranslationUnitDecl()); - // We sometimes skip loading namespace-level results (they tend to be huge). - bool Load = LoadExternal || - !(isa<TranslationUnitDecl>(Ctx) || isa<NamespaceDecl>(Ctx)); - // Enumerate all of the results in this context. - for (DeclContextLookupResult R : - Load ? Ctx->lookups() - : Ctx->noload_lookups(/*PreserveInternalState=*/false)) { - for (auto *D : R) { - if (auto *ND = Result.getAcceptableDecl(D)) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); - Visited.add(ND); - } - } - } - - // Traverse using directives for qualified name lookup. - if (QualifiedNameLookup) { ShadowContextRAII Shadow(Visited); - for (auto I : Ctx->using_directives()) { - if (!Result.getSema().isVisible(I)) - continue; - LookupVisibleDecls(I->getNominatedNamespace(), Result, - QualifiedNameLookup, InBaseClass, Consumer, Visited, - IncludeDependentBases, LoadExternal); - } + lookupInDeclContext(Ctx, Result, /*QualifiedNameLookup=*/true, + /*InBaseClass=*/false); } - // Traverse the contexts of inherited C++ classes. - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) { - if (!Record->hasDefinition()) +private: + void lookupInDeclContext(DeclContext *Ctx, LookupResult &Result, + bool QualifiedNameLookup, bool InBaseClass) { + if (!Ctx) return; - for (const auto &B : Record->bases()) { - QualType BaseType = B.getType(); + // Make sure we don't visit the same context twice. + if (Visited.visitedContext(Ctx->getPrimaryContext())) + return; - RecordDecl *RD; - if (BaseType->isDependentType()) { - if (!IncludeDependentBases) { - // Don't look into dependent bases, because name lookup can't look - // there anyway. - continue; + Consumer.EnteredContext(Ctx); + + // Outside C++, lookup results for the TU live on identifiers. + if (isa<TranslationUnitDecl>(Ctx) && + !Result.getSema().getLangOpts().CPlusPlus) { + auto &S = Result.getSema(); + auto &Idents = S.Context.Idents; + + // Ensure all external identifiers are in the identifier table. + if (LoadExternal) + if (IdentifierInfoLookup *External = + Idents.getExternalIdentifierLookup()) { + std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers()); + for (StringRef Name = Iter->Next(); !Name.empty(); + Name = Iter->Next()) + Idents.get(Name); + } + + // Walk all lookup results in the TU for each identifier. + for (const auto &Ident : Idents) { + for (auto I = S.IdResolver.begin(Ident.getValue()), + E = S.IdResolver.end(); + I != E; ++I) { + if (S.IdResolver.isDeclInScope(*I, Ctx)) { + if (NamedDecl *ND = Result.getAcceptableDecl(*I)) { + Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); + Visited.add(ND); + } + } } - const auto *TST = BaseType->getAs<TemplateSpecializationType>(); - if (!TST) - continue; - TemplateName TN = TST->getTemplateName(); - const auto *TD = - dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl()); - if (!TD) - continue; - RD = TD->getTemplatedDecl(); - } else { - const auto *Record = BaseType->getAs<RecordType>(); - if (!Record) - continue; - RD = Record->getDecl(); } - // FIXME: It would be nice to be able to determine whether referencing - // a particular member would be ambiguous. For example, given - // - // struct A { int member; }; - // struct B { int member; }; - // struct C : A, B { }; - // - // void f(C *c) { c->### } - // - // accessing 'member' would result in an ambiguity. However, we - // could be smart enough to qualify the member with the base - // class, e.g., - // - // c->B::member - // - // or - // - // c->A::member - - // Find results in this base class (and its bases). - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(RD, Result, QualifiedNameLookup, /*InBaseClass=*/true, - Consumer, Visited, IncludeDependentBases, - LoadExternal); + return; } - } - // Traverse the contexts of Objective-C classes. - if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) { - // Traverse categories. - for (auto *Cat : IFace->visible_categories()) { - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(Cat, Result, QualifiedNameLookup, false, Consumer, - Visited, IncludeDependentBases, LoadExternal); + if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) + Result.getSema().ForceDeclarationOfImplicitMembers(Class); + + // We sometimes skip loading namespace-level results (they tend to be huge). + bool Load = LoadExternal || + !(isa<TranslationUnitDecl>(Ctx) || isa<NamespaceDecl>(Ctx)); + // Enumerate all of the results in this context. + for (DeclContextLookupResult R : + Load ? Ctx->lookups() + : Ctx->noload_lookups(/*PreserveInternalState=*/false)) { + for (auto *D : R) { + if (auto *ND = Result.getAcceptableDecl(D)) { + Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); + Visited.add(ND); + } + } } - // Traverse protocols. - for (auto *I : IFace->all_referenced_protocols()) { + // Traverse using directives for qualified name lookup. + if (QualifiedNameLookup) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, - Visited, IncludeDependentBases, LoadExternal); + for (auto I : Ctx->using_directives()) { + if (!Result.getSema().isVisible(I)) + continue; + lookupInDeclContext(I->getNominatedNamespace(), Result, + QualifiedNameLookup, InBaseClass); + } } - // Traverse the superclass. - if (IFace->getSuperClass()) { - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup, - true, Consumer, Visited, IncludeDependentBases, - LoadExternal); - } + // Traverse the contexts of inherited C++ classes. + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) { + if (!Record->hasDefinition()) + return; - // If there is an implementation, traverse it. We do this to find - // synthesized ivars. - if (IFace->getImplementation()) { - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(IFace->getImplementation(), Result, - QualifiedNameLookup, InBaseClass, Consumer, Visited, - IncludeDependentBases, LoadExternal); - } - } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) { - for (auto *I : Protocol->protocols()) { - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, - Visited, IncludeDependentBases, LoadExternal); - } - } else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) { - for (auto *I : Category->protocols()) { - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, - Visited, IncludeDependentBases, LoadExternal); + for (const auto &B : Record->bases()) { + QualType BaseType = B.getType(); + + RecordDecl *RD; + if (BaseType->isDependentType()) { + if (!IncludeDependentBases) { + // Don't look into dependent bases, because name lookup can't look + // there anyway. + continue; + } + const auto *TST = BaseType->getAs<TemplateSpecializationType>(); + if (!TST) + continue; + TemplateName TN = TST->getTemplateName(); + const auto *TD = + dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl()); + if (!TD) + continue; + RD = TD->getTemplatedDecl(); + } else { + const auto *Record = BaseType->getAs<RecordType>(); + if (!Record) + continue; + RD = Record->getDecl(); + } + + // FIXME: It would be nice to be able to determine whether referencing + // a particular member would be ambiguous. For example, given + // + // struct A { int member; }; + // struct B { int member; }; + // struct C : A, B { }; + // + // void f(C *c) { c->### } + // + // accessing 'member' would result in an ambiguity. However, we + // could be smart enough to qualify the member with the base + // class, e.g., + // + // c->B::member + // + // or + // + // c->A::member + + // Find results in this base class (and its bases). + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(RD, Result, QualifiedNameLookup, + /*InBaseClass=*/true); + } } - // If there is an implementation, traverse it. - if (Category->getImplementation()) { - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(Category->getImplementation(), Result, - QualifiedNameLookup, true, Consumer, Visited, - IncludeDependentBases, LoadExternal); + // Traverse the contexts of Objective-C classes. + if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) { + // Traverse categories. + for (auto *Cat : IFace->visible_categories()) { + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(Cat, Result, QualifiedNameLookup, + /*InBaseClass=*/false); + } + + // Traverse protocols. + for (auto *I : IFace->all_referenced_protocols()) { + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(I, Result, QualifiedNameLookup, + /*InBaseClass=*/false); + } + + // Traverse the superclass. + if (IFace->getSuperClass()) { + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(IFace->getSuperClass(), Result, QualifiedNameLookup, + /*InBaseClass=*/true); + } + + // If there is an implementation, traverse it. We do this to find + // synthesized ivars. + if (IFace->getImplementation()) { + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(IFace->getImplementation(), Result, + QualifiedNameLookup, InBaseClass); + } + } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) { + for (auto *I : Protocol->protocols()) { + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(I, Result, QualifiedNameLookup, + /*InBaseClass=*/false); + } + } else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) { + for (auto *I : Category->protocols()) { + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(I, Result, QualifiedNameLookup, + /*InBaseClass=*/false); + } + + // If there is an implementation, traverse it. + if (Category->getImplementation()) { + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(Category->getImplementation(), Result, + QualifiedNameLookup, /*InBaseClass=*/true); + } } } -} -static void LookupVisibleDecls(Scope *S, LookupResult &Result, - UnqualUsingDirectiveSet &UDirs, - VisibleDeclConsumer &Consumer, - VisibleDeclsRecord &Visited, - bool LoadExternal) { - if (!S) - return; + void lookupInScope(Scope *S, LookupResult &Result, + UnqualUsingDirectiveSet &UDirs) { + // No clients run in this mode and it's not supported. Please add tests and + // remove the assertion if you start relying on it. + assert(!IncludeDependentBases && "Unsupported flag for lookupInScope"); - if (!S->getEntity() || - (!S->getParent() && - !Visited.alreadyVisitedContext(S->getEntity())) || - (S->getEntity())->isFunctionOrMethod()) { - FindLocalExternScope FindLocals(Result); - // Walk through the declarations in this Scope. The consumer might add new - // decls to the scope as part of deserialization, so make a copy first. - SmallVector<Decl *, 8> ScopeDecls(S->decls().begin(), S->decls().end()); - for (Decl *D : ScopeDecls) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) - if ((ND = Result.getAcceptableDecl(ND))) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND), nullptr, false); - Visited.add(ND); - } + if (!S) + return; + + if (!S->getEntity() || + (!S->getParent() && !Visited.alreadyVisitedContext(S->getEntity())) || + (S->getEntity())->isFunctionOrMethod()) { + FindLocalExternScope FindLocals(Result); + // Walk through the declarations in this Scope. The consumer might add new + // decls to the scope as part of deserialization, so make a copy first. + SmallVector<Decl *, 8> ScopeDecls(S->decls().begin(), S->decls().end()); + for (Decl *D : ScopeDecls) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) + if ((ND = Result.getAcceptableDecl(ND))) { + Consumer.FoundDecl(ND, Visited.checkHidden(ND), nullptr, false); + Visited.add(ND); + } + } } - } - // FIXME: C++ [temp.local]p8 - DeclContext *Entity = nullptr; - if (S->getEntity()) { - // Look into this scope's declaration context, along with any of its - // parent lookup contexts (e.g., enclosing classes), up to the point - // where we hit the context stored in the next outer scope. - Entity = S->getEntity(); - DeclContext *OuterCtx = findOuterContext(S).first; // FIXME - - for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx); - Ctx = Ctx->getLookupParent()) { - if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) { - if (Method->isInstanceMethod()) { - // For instance methods, look for ivars in the method's interface. - LookupResult IvarResult(Result.getSema(), Result.getLookupName(), - Result.getNameLoc(), Sema::LookupMemberName); - if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) { - LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited, - /*IncludeDependentBases=*/false, LoadExternal); + // FIXME: C++ [temp.local]p8 + DeclContext *Entity = nullptr; + if (S->getEntity()) { + // Look into this scope's declaration context, along with any of its + // parent lookup contexts (e.g., enclosing classes), up to the point + // where we hit the context stored in the next outer scope. + Entity = S->getEntity(); + DeclContext *OuterCtx = findOuterContext(S).first; // FIXME + + for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx); + Ctx = Ctx->getLookupParent()) { + if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) { + if (Method->isInstanceMethod()) { + // For instance methods, look for ivars in the method's interface. + LookupResult IvarResult(Result.getSema(), Result.getLookupName(), + Result.getNameLoc(), + Sema::LookupMemberName); + if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) { + lookupInDeclContext(IFace, IvarResult, + /*QualifiedNameLookup=*/false, + /*InBaseClass=*/false); + } } + + // We've already performed all of the name lookup that we need + // to for Objective-C methods; the next context will be the + // outer scope. + break; } - // We've already performed all of the name lookup that we need - // to for Objective-C methods; the next context will be the - // outer scope. - break; - } + if (Ctx->isFunctionOrMethod()) + continue; - if (Ctx->isFunctionOrMethod()) - continue; + lookupInDeclContext(Ctx, Result, /*QualifiedNameLookup=*/false, + /*InBaseClass=*/false); + } + } else if (!S->getParent()) { + // Look into the translation unit scope. We walk through the translation + // unit's declaration context, because the Scope itself won't have all of + // the declarations if we loaded a precompiled header. + // FIXME: We would like the translation unit's Scope object to point to + // the translation unit, so we don't need this special "if" branch. + // However, doing so would force the normal C++ name-lookup code to look + // into the translation unit decl when the IdentifierInfo chains would + // suffice. Once we fix that problem (which is part of a more general + // "don't look in DeclContexts unless we have to" optimization), we can + // eliminate this. + Entity = Result.getSema().Context.getTranslationUnitDecl(); + lookupInDeclContext(Entity, Result, /*QualifiedNameLookup=*/false, + /*InBaseClass=*/false); + } - LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited, - /*IncludeDependentBases=*/false, LoadExternal); + if (Entity) { + // Lookup visible declarations in any namespaces found by using + // directives. + for (const UnqualUsingEntry &UUE : UDirs.getNamespacesFor(Entity)) + lookupInDeclContext( + const_cast<DeclContext *>(UUE.getNominatedNamespace()), Result, + /*QualifiedNameLookup=*/false, + /*InBaseClass=*/false); } - } else if (!S->getParent()) { - // Look into the translation unit scope. We walk through the translation - // unit's declaration context, because the Scope itself won't have all of - // the declarations if we loaded a precompiled header. - // FIXME: We would like the translation unit's Scope object to point to the - // translation unit, so we don't need this special "if" branch. However, - // doing so would force the normal C++ name-lookup code to look into the - // translation unit decl when the IdentifierInfo chains would suffice. - // Once we fix that problem (which is part of a more general "don't look - // in DeclContexts unless we have to" optimization), we can eliminate this. - Entity = Result.getSema().Context.getTranslationUnitDecl(); - LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited, - /*IncludeDependentBases=*/false, LoadExternal); - } - if (Entity) { - // Lookup visible declarations in any namespaces found by using - // directives. - for (const UnqualUsingEntry &UUE : UDirs.getNamespacesFor(Entity)) - LookupVisibleDecls(const_cast<DeclContext *>(UUE.getNominatedNamespace()), - Result, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited, - /*IncludeDependentBases=*/false, LoadExternal); + // Lookup names in the parent scope. + ShadowContextRAII Shadow(Visited); + lookupInScope(S->getParent(), Result, UDirs); } - // Lookup names in the parent scope. - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(S->getParent(), Result, UDirs, Consumer, Visited, - LoadExternal); -} +private: + VisibleDeclsRecord Visited; + VisibleDeclConsumer &Consumer; + bool IncludeDependentBases; + bool LoadExternal; +}; +} // namespace void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope, bool LoadExternal) { - // Determine the set of using directives available during - // unqualified name lookup. - Scope *Initial = S; - UnqualUsingDirectiveSet UDirs(*this); - if (getLangOpts().CPlusPlus) { - // Find the first namespace or translation-unit scope. - while (S && !isNamespaceOrTranslationUnitScope(S)) - S = S->getParent(); - - UDirs.visitScopeChain(Initial, S); - } - UDirs.done(); - - // Look for visible declarations. - LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); - Result.setAllowHidden(Consumer.includeHiddenDecls()); - VisibleDeclsRecord Visited; - if (!IncludeGlobalScope) - Visited.visitedContext(Context.getTranslationUnitDecl()); - ShadowContextRAII Shadow(Visited); - ::LookupVisibleDecls(Initial, Result, UDirs, Consumer, Visited, LoadExternal); + LookupVisibleHelper H(Consumer, /*IncludeDependentBases=*/false, + LoadExternal); + H.lookupVisibleDecls(*this, S, Kind, IncludeGlobalScope); } void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope, bool IncludeDependentBases, bool LoadExternal) { - LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); - Result.setAllowHidden(Consumer.includeHiddenDecls()); - VisibleDeclsRecord Visited; - if (!IncludeGlobalScope) - Visited.visitedContext(Context.getTranslationUnitDecl()); - ShadowContextRAII Shadow(Visited); - ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, - /*InBaseClass=*/false, Consumer, Visited, - IncludeDependentBases, LoadExternal); + LookupVisibleHelper H(Consumer, IncludeDependentBases, LoadExternal); + H.lookupVisibleDecls(*this, Ctx, Kind, IncludeGlobalScope); } /// LookupOrCreateLabel - Do a name lookup of a label with the specified name. @@ -4745,7 +4863,7 @@ std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer( // occurs). Note that CorrectionCandidateCallback is polymorphic and // initially stack-allocated. std::unique_ptr<CorrectionCandidateCallback> ClonedCCC = CCC.clone(); - auto Consumer = llvm::make_unique<TypoCorrectionConsumer>( + auto Consumer = std::make_unique<TypoCorrectionConsumer>( *this, TypoName, LookupKind, S, SS, std::move(ClonedCCC), MemberContext, EnteringContext); @@ -5164,8 +5282,11 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) { return FD->getDefinition(); if (TagDecl *TD = dyn_cast<TagDecl>(D)) return TD->getDefinition(); + // The first definition for this ObjCInterfaceDecl might be in the TU + // and not associated with any module. Use the one we know to be complete + // and have just seen in a module. if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) - return ID->getDefinition(); + return ID; if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) return PD->getDefinition(); if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) @@ -5361,6 +5482,8 @@ TypoExpr *Sema::createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC, State.Consumer = std::move(TCC); State.DiagHandler = std::move(TDG); State.RecoveryHandler = std::move(TRC); + if (TE) + TypoExprs.push_back(TE); return TE; } |