aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaLookup.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaLookup.cpp')
-rw-r--r--lib/Sema/SemaLookup.cpp853
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;
}