Skip to content

Commit

Permalink
[FOLD] apply cwg1835 in all c++ language modes
Browse files Browse the repository at this point in the history
  • Loading branch information
sdkrystian committed Oct 22, 2024
1 parent 317d939 commit 9c5a139
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 58 deletions.
66 changes: 30 additions & 36 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,36 +409,6 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
LookupParsedName(Found, S, &SS, ObjectType,
/*AllowBuiltinCreation=*/false, EnteringContext);

bool IsDependent = Found.wasNotFoundInCurrentInstantiation();

bool ObjectTypeSearchedInScope = false;

// C++ [basic.lookup.qual.general]p2:
// A member-qualified name is the (unique) component name, if any, of
// - an unqualified-id or
// - a nested-name-specifier of the form type-name :: or namespace-name ::
// in the id-expression of a class member access expression.
//
// C++ [basic.lookup.qual.general]p3:
// [...] If nothing is found by qualified lookup for a member-qualified
// name that is the terminal name of a nested-name-specifier and is not
// dependent, it undergoes unqualified lookup.
//
// In 'x.A::B::y', 'A' will undergo unqualified lookup if qualified lookup
// in the type of 'x' finds nothing. If the lookup context is dependent,
// we perform the unqualified lookup in the template definition context
// and store the results so we can replicate the lookup during instantiation.
if (MayBeNNS && Found.empty() && !ObjectType.isNull() &&
(!getLangOpts().CPlusPlus23 || !IsDependent)) {
if (S) {
LookupName(Found, S);
} else if (!SS.getUnqualifiedLookups().empty()) {
Found.addAllDecls(SS.getUnqualifiedLookups());
Found.resolveKind();
}
ObjectTypeSearchedInScope = true;
}

// C++ [basic.lookup.qual.general]p3:
// [...] Unless otherwise specified, a qualified name undergoes qualified
// name lookup in its lookup context from the point where it appears unless
Expand Down Expand Up @@ -474,6 +444,33 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
if (Found.wasNotFoundInCurrentInstantiation())
return false;

bool ObjectTypeSearchedInScope = false;

// C++ [basic.lookup.qual.general]p2:
// A member-qualified name is the (unique) component name, if any, of
// - an unqualified-id or
// - a nested-name-specifier of the form type-name :: or namespace-name ::
// in the id-expression of a class member access expression.
//
// C++ [basic.lookup.qual.general]p3:
// [...] If nothing is found by qualified lookup for a member-qualified
// name that is the terminal name of a nested-name-specifier and is not
// dependent, it undergoes unqualified lookup.
//
// In 'x.A::B::y', 'A' will undergo unqualified lookup if qualified lookup
// in the type of 'x' finds nothing. If the lookup context is dependent,
// we perform the unqualified lookup in the template definition context
// and store the results so we can replicate the lookup during instantiation.
if (MayBeNNS && Found.empty() && !ObjectType.isNull()) {
if (S) {
LookupName(Found, S);
} else if (!SS.getUnqualifiedLookups().empty()) {
Found.addAllDecls(SS.getUnqualifiedLookups());
Found.resolveKind();
}
ObjectTypeSearchedInScope = true;
}

if (Found.isAmbiguous())
return false;

Expand Down Expand Up @@ -503,7 +500,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
}
}

if (Found.empty() && AllowTypoCorrection && !IsDependent) {
if (Found.empty() && AllowTypoCorrection) {
// If we did not find any names, and this is not a disambiguation, attempt
// to correct any typos.
DeclarationName Name = Found.getLookupName();
Expand Down Expand Up @@ -544,12 +541,9 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,

NamedDecl *ExampleLookupResult =
Found.empty() ? nullptr : Found.getRepresentativeDecl();
FilterAcceptableTemplateNames(Found, getLangOpts().CPlusPlus23 ||
!ObjectTypeSearchedInScope);
FilterAcceptableTemplateNames(Found);
if (Found.empty()) {
if (IsDependent) {
Found.setNotFoundInCurrentInstantiation();
} else if (ExampleLookupResult && RequiredTemplate) {
if (ExampleLookupResult && RequiredTemplate) {
// If a 'template' keyword was used, a lookup that finds only non-template
// names is an error.
Diag(Found.getNameLoc(), diag::err_template_kw_refers_to_non_template)
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CXX/class.derived/class.member.lookup/p8.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ template<typename T>
void DerivedT<T>::Inner() {
Derived1T<T>::Foo();
Derived2T<T>::Member = 42;
this->Derived1T<T>::Foo();
this->Derived2T<T>::Member = 42;
this->Derived1T<T>::Foo(); // expected-warning {{use 'template' keyword to treat 'Derived1T' as a dependent template name}}
this->Derived2T<T>::Member = 42; // expected-warning {{use 'template' keyword to treat 'Derived2T' as a dependent template name}}
this->Foo(); // expected-error{{non-static member 'Foo' found in multiple base-class subobjects of type 'BaseT<int>'}}
}

Expand Down
18 changes: 8 additions & 10 deletions clang/test/CXX/drs/cwg1xx.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify=expected,cxx98,cxx98-11,cxx98-14,cxx98-17,cxx98-20 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx98-11,cxx98-14,cxx98-17,cxx98-20,cxx11-14 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx98-14,cxx98-17,cxx98-20,cxx11-14 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx17,cxx98-17,cxx98-20 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx17,cxx98-20 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx17,since-cxx23 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify=expected,cxx98,cxx98-11,cxx98-14,cxx98-17 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx98-11,cxx98-14,cxx98-17,cxx11-14 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx98-14,cxx98-17,cxx11-14 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx17,cxx98-17 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors

#if __cplusplus == 199711L
#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
Expand Down Expand Up @@ -705,8 +705,6 @@ namespace cwg141 { // cwg141: 3.1
// expected-note@#cwg141-S {{'::cwg141::S<int>::n' declared here}}
b.f<int>();
// expected-error@-1 {{no member named 'f' in 'cwg141::B'}}
// cxx98-20-error@-2 {{expected '(' for function-style cast or type construction}}
// cxx98-20-error@-3 {{expected expression}}
(void)b.S<int>::n;
}
template<typename T> struct C {
Expand All @@ -717,11 +715,11 @@ namespace cwg141 { // cwg141: 3.1
}
void h() {
(void)t.S<int>::n;
// since-cxx23-error@-1 {{use 'template' keyword to treat 'S' as a dependent template name}}
// expected-error@-1 {{use 'template' keyword to treat 'S' as a dependent template name}}
}
void i() {
(void)t.S<int>();
// since-cxx23-error@-1 {{use 'template' keyword to treat 'S' as a dependent template name}}
// expected-error@-1 {{use 'template' keyword to treat 'S' as a dependent template name}}
}
};
void h() { C<B>().h(); } // ok
Expand Down
10 changes: 4 additions & 6 deletions clang/test/SemaCXX/pseudo-destructors.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -emit-llvm-only -std=c++11 -verify=expected,cxx98-20 %s
// RUN: %clang_cc1 -emit-llvm-only -std=c++23 -verify=expected,since-cxx23 %s
// RUN: %clang_cc1 -emit-llvm-only -verify -std=c++11 %s
struct A {};

enum Foo { F };
Expand Down Expand Up @@ -149,13 +148,12 @@ namespace TwoPhaseLookup {
namespace Template {
template<typename T> struct Y {};
template<class U> using G = Y<U>;
template<typename T> void f(T *p) { p->~G<int>(); } // since-cxx23-error {{no member named 'G'}}
// cxx98-20-error@-1 {{no member named '~Y' in 'TwoPhaseLookup::Template::N::G<int>'}}
template<typename T> void f(T *p) { p->~G<int>(); } // expected-error {{no member named 'G'}}
void h1(Y<int> *p) { p->~G<int>(); }
void h2(Y<int> *p) { f(p); } // since-cxx23-note {{in instantiation of}}
void h2(Y<int> *p) { f(p); } // expected-note {{in instantiation of}}
namespace N { template<typename T> struct G {}; }
void h3(N::G<int> *p) { p->~G<int>(); }
void h4(N::G<int> *p) { f(p); } // cxx98-20-note {{in instantiation of}}
void h4(N::G<int> *p) { f(p); }
}

namespace TemplateUndeclared {
Expand Down
3 changes: 2 additions & 1 deletion clang/test/SemaCXX/static-assert-cxx17.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ void foo6() {
// expected-error@-1{{static assertion failed due to requirement '(const X<int>[0]){} == nullptr'}}
static_assert(sizeof(X<decltype(X<typename T::T>().X<typename T::T>::~X())>) == 0);
// expected-error@-1{{static assertion failed due to requirement 'sizeof(X<void>) == 0'}} \
// expected-note@-1 {{evaluates to '8 == 0'}}
// expected-note@-1 {{evaluates to '8 == 0'}} \
// expected-warning@-1 {{use 'template' keyword to treat 'X' as a dependent template name}}
static_assert(constexpr_return_false<typename T::T, typename T::U>());
// expected-error@-1{{static assertion failed due to requirement 'constexpr_return_false<int, float>()'}}
}
Expand Down
8 changes: 5 additions & 3 deletions clang/test/SemaTemplate/dependent-template-recover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ struct X {

t->operator+<U const, 1>(1); // expected-warning{{use 'template' keyword to treat 'operator +' as a dependent template name}}
t->f1<int const, 2>(1); // expected-warning{{use 'template' keyword to treat 'f1' as a dependent template name}}
t->f1<3, int const>(1); // expected-error{{missing 'template' keyword prior to dependent template name 'f1'}}
t->f1<3, int const>(1); // expected-warning{{use 'template' keyword to treat 'f1' as a dependent template name}}

T::getAs<U>(); // expected-warning{{use 'template' keyword to treat 'getAs' as a dependent template name}}
t->T::getAs<U>(); // expected-warning{{use 'template' keyword to treat 'getAs' as a dependent template name}}

(*t).f2<N>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}
(*t).f2<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}
T::f2<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}
T::f2<0, int>(0); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}
T::f2<0, int>(0); // expected-warning{{use 'template' keyword to treat 'f2' as a dependent template name}}

T::foo<N < 2 || N >= 4>(); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}}

Expand Down Expand Up @@ -83,12 +83,14 @@ template<int N, typename T> void f(T t) {
T::g<mb>(0);

// ... but this one must be a template-id.
T::g<mb, int>(0); // expected-error {{missing 'template' keyword prior to dependent template name 'g'}}
T::g<mb, int>(0); // expected-warning {{use 'template' keyword to treat 'g' as a dependent template name}}
// expected-error@-1 {{no matching function for call to 'g'}}
}

struct Y {
template <int> void f(int);
template <int = 0> static void g(int); // expected-warning 0-1{{extension}}
// expected-note@-1 {{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}}
};
void q() { void (*p)(int) = Y::g; }
template void f<0>(Y); // expected-note {{in instantiation of}}
Expand Down

0 comments on commit 9c5a139

Please sign in to comment.