-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Clang c++ compiles error with struct in template class and < operator #81731
Comments
@llvm/issue-subscribers-clang-frontend Author: Bo Wang (wangbo15)
Please consider the following code:
template<class T>
class confused{};
template<class T>
class test
{
void foo() {
if(this->b.confused < 1);
};
struct bar
{
int confused;
} b;
}; Clang rejects it by giving such considerably puzzling output: <source>:8:32: error: expected '>'
8 | if(this->b.confused < 1);
| ^
<source>:8:29: note: to match this '<'
8 | if(this->b.confused < 1);
| ^
<source>:8:32: error: expected unqualified-id
8 | if(this->b.confused < 1);
| ^
<source>:8:33: warning: if statement has empty body [-Wempty-body]
8 | if(this->b.confused < 1);
| ^
<source>:8:33: note: put the semicolon on a separate line to silence this warning
1 warning and 2 errors generated.
Compiler returned: 1 We suppose that's because the compiler has found incorrect local variable name of Please check https://godbolt.org/z/7afqsvEvo. |
This goes all the way back to clang-3.0: https://godbolt.org/z/srY7rsW94 I am surprised we have not seen this before. Could be related to: #78213 Maybe related to: #16855 |
The main difference between https://godbolt.org/z/d8dY8e779 and https://godbolt.org/z/ovqssd9Y8 is here: llvm-project/clang/lib/Sema/SemaTemplate.cpp Lines 459 to 468 in 5a82daa
In the bad case llvm-project/clang/lib/Sema/SemaTemplate.cpp Lines 227 to 228 in 5a82daa
In the working case llvm-project/clang/lib/Parse/ParseExprCXX.cpp Lines 514 to 520 in 5a82daa
It is not clear to me what we need to do differently here. It is not till after the call here: llvm-project/clang/lib/Parse/ParseExpr.cpp Lines 2231 to 2233 in bfbd0da
that we finally make an attempt to call CC @zygoloid maybe you have an idea |
If you look at a bunch of the examples in basic.lookup.qual.general there does not seem to be a nice simple heuristic to determining if I should consider the name found valid or not. Apparently MSVC is the only once to get all these correct: https://godbolt.org/z/14W8KETz8 int f();
struct A {
int B, C;
template<int> using D = void;
using T = void;
void f();
};
using B = A;
template<int> using C = A;
template<int> using D = A;
template<int> using X = A;
template<class T>
void g(T *p) { // as instantiated for g<A>:
p->X<0>::f(); // error: A::X not found in ((p->X) < 0) > ::f()
p->template X<0>::f(); // OK, ::X found in definition context
p->B::f(); // OK, non-type A::B ignored
p->template C<0>::f(); // error: A::C is not a template
p->template D<0>::f(); // error: A::D<0> is not a class type
p->T::f(); // error: A::T is not a class type
}
template void g(A*); I think the reason clang fails on these cases is the same underlying issue here. |
I attempted to do extra filtering in if (R.empty())
return TNK_Non_template;
else if (!ObjectType.isNull() && R.isSingleResult())
if (CXXRecordDecl *RD = ObjectType->getAsCXXRecordDecl()) {
if (NamedDecl *ND = R.getFoundDecl()) {
if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(ND))
if (CXXRecordDecl *RDF = dyn_cast<CXXRecordDecl>(CTD->getTemplatedDecl())) {
bool AnyEqual = false;
if (RD->getMostRecentDecl() == RDF->getMostRecentDecl())
AnyEqual = true;
for ( auto base : RD->getMostRecentDecl()->bases() ) {
if (!base.getType().isNull() &&
base.getType()->getAsCXXRecordDecl() &&
base.getType()->getAsCXXRecordDecl()->getMostRecentDecl() == RDF->getMostRecentDecl())
AnyEqual = true;
if (!base.getType().isNull())
if (const TemplateSpecializationType *TST = base.getType()->getAs<TemplateSpecializationType>()) {
TemplateName TN = TST->getTemplateName();
if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(TN.getAsTemplateDecl()))
if (CXXRecordDecl *RDB = dyn_cast<CXXRecordDecl>(CTD->getTemplatedDecl()))
if (RDF->getMostRecentDecl() == RDB->getMostRecentDecl())
AnyEqual = true;
}
}
if (!AnyEqual)
return TNK_Non_template;
}
}
} It kind of works but I end up w/ a lot of duplicate diagnostics in several tests. It definitely feels hacky but there wasn't a more obvious place to do filtering. |
Clang is interpreting the template<class T>
class confused{ int x; };
template<class T>
class test
{
void foo() {
if(this->b.confused<int>::x);
};
struct bar
{
int confused;
} b;
};
template<> class test<int>::bar : confused<int> { };
// now test<int>::foo() accesses the confused<int>::x member in b The rules here were changed by P1787R6. It used to be that if a member lookup was dependent and the name was followed by It looks like Clang doesn't implement this part of P1787R6 yet. |
I'll try to give a bit more context about what's happening in each case:
Here, the lookup for
Here, the If there were a member template named
Right, this lookup for
This is fine when parsing the template, and parses as a template-id not as a less-than comparison, but fails during instantiation because
Like the previous example, this is fine when parsing the template, but fails in instantiation because
This names |
Please consider the following code:
Clang rejects it by giving such considerably puzzling output:
We suppose that's because the compiler has found incorrect local variable name of
confused
by confusing the global template class declared above with the integer member variable declared in the nested classbar
insidetest
Please check https://godbolt.org/z/7afqsvEvo.
The text was updated successfully, but these errors were encountered: