[clang] Add the check of membership in decltype for the issue #58674
D137531 had once fixed the issue. However, it caused a crash during compiling llvm/unittests/IR/PatternMatch.cpp in stage-2. The reason is the predicator isDerivedFrom does not consider independent types if the derived type is dependent. This patch improves D137531 by adding an option to make isDerivedFrom consider independent types. Differential Revision: https://reviews.llvm.org/D142437
This commit is contained in:
@@ -57,6 +57,9 @@ Bug Fixes
|
||||
- Fix crash on invalid code when looking up a destructor in a templated class
|
||||
inside a namespace. This fixes
|
||||
`Issue 59446 <https://github.com/llvm/llvm-project/issues/59446>`_.
|
||||
- Fix an issue about ``decltype`` in the members of class templates derived from
|
||||
templates with related parameters. This fixes
|
||||
`Issue 58674 <https://github.com/llvm/llvm-project/issues/58674>`_.
|
||||
|
||||
Improvements to Clang's diagnostics
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -1547,7 +1547,8 @@ public:
|
||||
/// \param Base the base class we are searching for.
|
||||
///
|
||||
/// \returns true if this class is derived from Base, false otherwise.
|
||||
bool isDerivedFrom(const CXXRecordDecl *Base) const;
|
||||
bool isDerivedFrom(const CXXRecordDecl *Base,
|
||||
bool LookupIndependent = false) const;
|
||||
|
||||
/// Determine whether this class is derived from the type \p Base.
|
||||
///
|
||||
@@ -1565,7 +1566,8 @@ public:
|
||||
///
|
||||
/// \todo add a separate parameter to configure IsDerivedFrom, rather than
|
||||
/// tangling input and output in \p Paths
|
||||
bool isDerivedFrom(const CXXRecordDecl *Base, CXXBasePaths &Paths) const;
|
||||
bool isDerivedFrom(const CXXRecordDecl *Base, CXXBasePaths &Paths,
|
||||
bool LookupIndependent = false) const;
|
||||
|
||||
/// Determine whether this class is virtually derived from
|
||||
/// the class \p Base.
|
||||
|
||||
@@ -64,14 +64,16 @@ void CXXBasePaths::swap(CXXBasePaths &Other) {
|
||||
std::swap(DetectedVirtual, Other.DetectedVirtual);
|
||||
}
|
||||
|
||||
bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base) const {
|
||||
bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base,
|
||||
bool LookupIndependent) const {
|
||||
CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false,
|
||||
/*DetectVirtual=*/false);
|
||||
return isDerivedFrom(Base, Paths);
|
||||
return isDerivedFrom(Base, Paths, LookupIndependent);
|
||||
}
|
||||
|
||||
bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base,
|
||||
CXXBasePaths &Paths) const {
|
||||
CXXBasePaths &Paths,
|
||||
bool LookupIndependent) const {
|
||||
if (getCanonicalDecl() == Base->getCanonicalDecl())
|
||||
return false;
|
||||
|
||||
@@ -80,9 +82,10 @@ bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base,
|
||||
const CXXRecordDecl *BaseDecl = Base->getCanonicalDecl();
|
||||
return lookupInBases(
|
||||
[BaseDecl](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
|
||||
return FindBaseClass(Specifier, Path, BaseDecl);
|
||||
return Specifier->getType()->getAsRecordDecl() &&
|
||||
FindBaseClass(Specifier, Path, BaseDecl);
|
||||
},
|
||||
Paths);
|
||||
Paths, LookupIndependent);
|
||||
}
|
||||
|
||||
bool CXXRecordDecl::isVirtuallyDerivedFrom(const CXXRecordDecl *Base) const {
|
||||
|
||||
@@ -2693,20 +2693,36 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
|
||||
// to get this right here so that we don't end up making a
|
||||
// spuriously dependent expression if we're inside a dependent
|
||||
// instance method.
|
||||
//
|
||||
// We also don't need to do this if R resolved to a member in another
|
||||
// class, which can happen in an unevaluated operand:
|
||||
//
|
||||
// C++ [expr.prim.id]p3.3:
|
||||
// If that id-expression denotes a non-static data member and it
|
||||
// appears in an unevaluated operand.
|
||||
if (!R.empty() && (*R.begin())->isCXXClassMember()) {
|
||||
bool MightBeImplicitMember;
|
||||
if (!IsAddressOfOperand)
|
||||
MightBeImplicitMember = true;
|
||||
else if (!SS.isEmpty())
|
||||
MightBeImplicitMember = false;
|
||||
else if (R.isOverloadedResult())
|
||||
MightBeImplicitMember = false;
|
||||
else if (R.isUnresolvableResult())
|
||||
MightBeImplicitMember = true;
|
||||
else
|
||||
MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl()) ||
|
||||
isa<IndirectFieldDecl>(R.getFoundDecl()) ||
|
||||
isa<MSPropertyDecl>(R.getFoundDecl());
|
||||
bool MightBeImplicitMember = true, CheckField = true;
|
||||
if (IsAddressOfOperand) {
|
||||
MightBeImplicitMember = SS.isEmpty() && !R.isOverloadedResult();
|
||||
CheckField = !R.isUnresolvableResult();
|
||||
}
|
||||
if (MightBeImplicitMember && CheckField) {
|
||||
if (R.isSingleResult() &&
|
||||
isa<FieldDecl, IndirectFieldDecl, MSPropertyDecl>(R.getFoundDecl())) {
|
||||
auto Class = cast<CXXRecordDecl>((*R.begin())->getDeclContext());
|
||||
for (auto Curr = S->getLookupEntity(); Curr && !Curr->isFileContext();
|
||||
Curr = Curr->getParent()) {
|
||||
if (auto ThisClass = dyn_cast_if_present<CXXRecordDecl>(Curr)) {
|
||||
if ((MightBeImplicitMember =
|
||||
ThisClass->Equals(Class) ||
|
||||
ThisClass->isDerivedFrom(Class,
|
||||
/*LookupIndependent=*/true)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (IsAddressOfOperand)
|
||||
MightBeImplicitMember = false;
|
||||
}
|
||||
|
||||
if (MightBeImplicitMember)
|
||||
return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc,
|
||||
|
||||
@@ -101,6 +101,44 @@ namespace D5789 {
|
||||
template<class T> void foo(decltype(T(LP1{ .p1 = g1, .p1.x[1] = 'x' }))) {}
|
||||
}
|
||||
|
||||
namespace GH58674 {
|
||||
struct Foo {
|
||||
float value_;
|
||||
struct nested {
|
||||
float value_;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct TemplateFoo {
|
||||
float value_;
|
||||
};
|
||||
|
||||
float bar;
|
||||
|
||||
template <typename T>
|
||||
struct Animal{};
|
||||
|
||||
template <typename T>
|
||||
class Cat : Animal<T> {
|
||||
using okay = decltype(Foo::value_);
|
||||
using also_okay = decltype(bar);
|
||||
using okay2 = decltype(Foo::nested::value_);
|
||||
using okay3 = decltype(TemplateFoo<T>::value_);
|
||||
public:
|
||||
void meow() {
|
||||
using okay = decltype(Foo::value_);
|
||||
using also_okay = decltype(bar);
|
||||
using okay2 = decltype(Foo::nested::value_);
|
||||
using okay3 = decltype(TemplateFoo<T>::value_);
|
||||
}
|
||||
};
|
||||
|
||||
void baz() {
|
||||
Cat<void>{}.meow();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename>
|
||||
class conditional {
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user