Skip to content

Commit

Permalink
Refactor and simplify class scope name lookup.
Browse files Browse the repository at this point in the history
This is partly in preparation for an upcoming change that can change the
order in which DeclContext lookup results are presented.

In passing, fix some obvious errors where name lookup's notion of a
"static member function" missed static member function templates, and
where its notion of "same set of declarations" was confused by the same
declarations appearing in a different order.
  • Loading branch information
zygoloid committed Nov 26, 2020
1 parent 1363dfa commit 3fb0879
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 300 deletions.
Expand Up @@ -611,12 +611,10 @@ static StyleKind findStyleKind(

// If this method has the same name as any base method, this is likely
// necessary even if it's not an override. e.g. CRTP.
auto FindHidden = [&](const CXXBaseSpecifier *S, clang::CXXBasePath &P) {
return CXXRecordDecl::FindOrdinaryMember(S, P, Decl->getDeclName());
};
CXXBasePaths UnusedPaths;
if (Decl->getParent()->lookupInBases(FindHidden, UnusedPaths))
return SK_Invalid;
for (const CXXBaseSpecifier &Base : Decl->getParent()->bases())
if (const auto *RD = Base.getType()->getAsCXXRecordDecl())
if (RD->hasMemberName(Decl->getDeclName()))
return SK_Invalid;

if (Decl->isConstexpr() && NamingStyles[SK_ConstexprMethod])
return SK_ConstexprMethod;
Expand Down
62 changes: 9 additions & 53 deletions clang/include/clang/AST/DeclCXX.h
Expand Up @@ -1622,58 +1622,6 @@ class CXXRecordDecl : public RecordDecl {
CXXBasePath &Path,
const CXXRecordDecl *BaseRecord);

/// Base-class lookup callback that determines whether there exists
/// a tag with the given name.
///
/// This callback can be used with \c lookupInBases() to find tag members
/// of the given name within a C++ class hierarchy.
static bool FindTagMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, DeclarationName Name);

/// Base-class lookup callback that determines whether there exists
/// a member with the given name.
///
/// This callback can be used with \c lookupInBases() to find members
/// of the given name within a C++ class hierarchy.
static bool FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, DeclarationName Name);

/// Base-class lookup callback that determines whether there exists
/// a member with the given name.
///
/// This callback can be used with \c lookupInBases() to find members
/// of the given name within a C++ class hierarchy, including dependent
/// classes.
static bool
FindOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, DeclarationName Name);

/// Base-class lookup callback that determines whether there exists
/// an OpenMP declare reduction member with the given name.
///
/// This callback can be used with \c lookupInBases() to find members
/// of the given name within a C++ class hierarchy.
static bool FindOMPReductionMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, DeclarationName Name);

/// Base-class lookup callback that determines whether there exists
/// an OpenMP declare mapper member with the given name.
///
/// This callback can be used with \c lookupInBases() to find members
/// of the given name within a C++ class hierarchy.
static bool FindOMPMapperMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, DeclarationName Name);

/// Base-class lookup callback that determines whether there exists
/// a member with the given name that can be used in a nested-name-specifier.
///
/// This callback can be used with \c lookupInBases() to find members of
/// the given name within a C++ class hierarchy that can occur within
/// nested-name-specifiers.
static bool FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
DeclarationName Name);

/// Retrieve the final overriders for each virtual member
/// function in the class hierarchy where this class is the
/// most-derived class in the class hierarchy.
Expand All @@ -1682,12 +1630,20 @@ class CXXRecordDecl : public RecordDecl {
/// Get the indirect primary bases for this class.
void getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const;

/// Determine whether this class has a member with the given name, possibly
/// in a non-dependent base class.
///
/// No check for ambiguity is performed, so this should never be used when
/// implementing language semantics, but it may be appropriate for warnings,
/// static analysis, or similar.
bool hasMemberName(DeclarationName N) const;

/// Performs an imprecise lookup of a dependent name in this class.
///
/// This function does not follow strict semantic rules and should be used
/// only when lookup rules can be relaxed, e.g. indexing.
std::vector<const NamedDecl *>
lookupDependentName(const DeclarationName &Name,
lookupDependentName(DeclarationName Name,
llvm::function_ref<bool(const NamedDecl *ND)> Filter);

/// Renders and displays an inheritance diagram
Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -7268,9 +7268,9 @@ class Sema final {
/// considered valid results.
/// \param AllowDependent Whether unresolved using declarations (that might
/// name templates) should be considered valid results.
NamedDecl *getAsTemplateNameDecl(NamedDecl *D,
bool AllowFunctionTemplates = true,
bool AllowDependent = true);
static NamedDecl *getAsTemplateNameDecl(NamedDecl *D,
bool AllowFunctionTemplates = true,
bool AllowDependent = true);

enum TemplateNameIsRequiredTag { TemplateNameIsRequired };
/// Whether and why a template name is required in this lookup.
Expand Down
127 changes: 35 additions & 92 deletions clang/lib/AST/CXXInheritance.cpp
Expand Up @@ -402,54 +402,45 @@ bool CXXRecordDecl::FindVirtualBaseClass(const CXXBaseSpecifier *Specifier,
->getCanonicalDecl() == BaseRecord;
}

bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
DeclarationName Name) {
RecordDecl *BaseRecord =
Specifier->getType()->castAs<RecordType>()->getDecl();

for (Path.Decls = BaseRecord->lookup(Name);
!Path.Decls.empty();
Path.Decls = Path.Decls.slice(1)) {
if (Path.Decls.front()->isInIdentifierNamespace(IDNS_Tag))
return true;
}

return false;
static bool isOrdinaryMember(const NamedDecl *ND) {
return ND->isInIdentifierNamespace(Decl::IDNS_Ordinary | Decl::IDNS_Tag |
Decl::IDNS_Member);
}

static bool findOrdinaryMember(RecordDecl *BaseRecord, CXXBasePath &Path,
static bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,
DeclarationName Name) {
const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag |
Decl::IDNS_Member;
for (Path.Decls = BaseRecord->lookup(Name);
!Path.Decls.empty();
Path.Decls = Path.Decls.slice(1)) {
if (Path.Decls.front()->isInIdentifierNamespace(IDNS))
Path.Decls = RD->lookup(Name);
for (NamedDecl *ND : Path.Decls)
if (isOrdinaryMember(ND))
return true;
}

return false;
}

bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
DeclarationName Name) {
RecordDecl *BaseRecord =
Specifier->getType()->castAs<RecordType>()->getDecl();
return findOrdinaryMember(BaseRecord, Path, Name);
bool CXXRecordDecl::hasMemberName(DeclarationName Name) const {
CXXBasePath P;
if (findOrdinaryMember(this, P, Name))
return true;

CXXBasePaths Paths(false, false, false);
return lookupInBases(
[Name](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
return findOrdinaryMember(Specifier->getType()->getAsCXXRecordDecl(),
Path, Name);
},
Paths);
}

bool CXXRecordDecl::FindOrdinaryMemberInDependentClasses(
const CXXBaseSpecifier *Specifier, CXXBasePath &Path,
DeclarationName Name) {
static bool
findOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, DeclarationName Name) {
const TemplateSpecializationType *TST =
Specifier->getType()->getAs<TemplateSpecializationType>();
if (!TST) {
auto *RT = Specifier->getType()->getAs<RecordType>();
if (!RT)
return false;
return findOrdinaryMember(RT->getDecl(), Path, Name);
return findOrdinaryMember(cast<CXXRecordDecl>(RT->getDecl()), Path, Name);
}
TemplateName TN = TST->getTemplateName();
const auto *TD = dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
Expand All @@ -461,80 +452,32 @@ bool CXXRecordDecl::FindOrdinaryMemberInDependentClasses(
return findOrdinaryMember(RD, Path, Name);
}

bool CXXRecordDecl::FindOMPReductionMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
DeclarationName Name) {
RecordDecl *BaseRecord =
Specifier->getType()->castAs<RecordType>()->getDecl();

for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty();
Path.Decls = Path.Decls.slice(1)) {
if (Path.Decls.front()->isInIdentifierNamespace(IDNS_OMPReduction))
return true;
}

return false;
}

bool CXXRecordDecl::FindOMPMapperMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
DeclarationName Name) {
RecordDecl *BaseRecord =
Specifier->getType()->castAs<RecordType>()->getDecl();

for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty();
Path.Decls = Path.Decls.slice(1)) {
if (Path.Decls.front()->isInIdentifierNamespace(IDNS_OMPMapper))
return true;
}

return false;
}

bool CXXRecordDecl::
FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
DeclarationName Name) {
RecordDecl *BaseRecord =
Specifier->getType()->castAs<RecordType>()->getDecl();

for (Path.Decls = BaseRecord->lookup(Name);
!Path.Decls.empty();
Path.Decls = Path.Decls.slice(1)) {
// FIXME: Refactor the "is it a nested-name-specifier?" check
if (isa<TypedefNameDecl>(Path.Decls.front()) ||
Path.Decls.front()->isInIdentifierNamespace(IDNS_Tag))
return true;
}

return false;
}

std::vector<const NamedDecl *> CXXRecordDecl::lookupDependentName(
const DeclarationName &Name,
DeclarationName Name,
llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
std::vector<const NamedDecl *> Results;
// Lookup in the class.
DeclContext::lookup_result DirectResult = lookup(Name);
if (!DirectResult.empty()) {
for (const NamedDecl *ND : DirectResult) {
if (Filter(ND))
Results.push_back(ND);
}
return Results;
bool AnyOrdinaryMembers = false;
for (const NamedDecl *ND : lookup(Name)) {
if (isOrdinaryMember(ND))
AnyOrdinaryMembers = true;
if (Filter(ND))
Results.push_back(ND);
}
if (AnyOrdinaryMembers)
return Results;

// Perform lookup into our base classes.
CXXBasePaths Paths;
Paths.setOrigin(this);
if (!lookupInBases(
[&](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
return CXXRecordDecl::FindOrdinaryMemberInDependentClasses(
Specifier, Path, Name);
return findOrdinaryMemberInDependentClasses(Specifier, Path, Name);
},
Paths, /*LookupInDependent=*/true))
return Results;
for (const NamedDecl *ND : Paths.front().Decls) {
if (Filter(ND))
if (isOrdinaryMember(ND) && Filter(ND))
Results.push_back(ND);
}
return Results;
Expand Down

0 comments on commit 3fb0879

Please sign in to comment.