[clang] [Clang] prevent recovery call expression from proceeding with explicit attributes and undeclared templates (PR #107786)
Oleksandr T. via cfe-commits
cfe-commits at lists.llvm.org
Sat Sep 28 08:32:15 PDT 2024
https://github.com/a-tarasyuk updated https://github.com/llvm/llvm-project/pull/107786
>From e9948a1004cc2b486a0422d83e88392754e9f7e9 Mon Sep 17 00:00:00 2001
From: Oleksandr T <oleksandr.tarasiuk at outlook.com>
Date: Mon, 23 Sep 2024 17:17:30 +0300
Subject: [PATCH 1/2] [Clang] prevent recovery call expression from proceeding
with explicit attributes and undeclared templates
---
clang/docs/ReleaseNotes.rst | 2 ++
clang/include/clang/Sema/Sema.h | 4 ++-
clang/lib/Sema/SemaExpr.cpp | 12 +++++--
clang/lib/Sema/SemaOverload.cpp | 2 +-
.../SemaTemplate/recovery-crash-cxx20.cpp | 32 +++++++++++++++++++
5 files changed, 48 insertions(+), 4 deletions(-)
create mode 100644 clang/test/SemaTemplate/recovery-crash-cxx20.cpp
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b47e06cb0c5d68..110f75d739c072 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -424,6 +424,8 @@ Bug Fixes to C++ Support
- Fixed an assertion failure in debug mode, and potential crashes in release mode, when
diagnosing a failed cast caused indirectly by a failed implicit conversion to the type of the constructor parameter.
- Fixed an assertion failure by adjusting integral to boolean vector conversions (#GH108326)
+- Fixed an assertion failure when invoking recovery call expressions with explicit attributes
+ and undeclared templates. (#GH107047, #GH49093)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index e1c3a99cfa167e..b2eefdbd1c56d1 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6753,7 +6753,9 @@ class Sema final : public SemaBase {
///
/// Return \c true if the error is unrecoverable, or \c false if the caller
/// should attempt to recover using these lookup results.
- bool DiagnoseDependentMemberLookup(const LookupResult &R);
+ bool DiagnoseDependentMemberLookup(
+ const LookupResult &R,
+ TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr);
/// Diagnose an empty lookup.
///
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 66df9c969256a2..a5770ae8848517 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2385,7 +2385,15 @@ static void emitEmptyLookupTypoDiagnostic(
SemaRef.PDiag(NoteID));
}
-bool Sema::DiagnoseDependentMemberLookup(const LookupResult &R) {
+bool Sema::DiagnoseDependentMemberLookup(
+ const LookupResult &R, TemplateArgumentListInfo *ExplicitTemplateArgs) {
+ auto IsTemplated = [](NamedDecl *D) { return D->isTemplated(); };
+ if (ExplicitTemplateArgs && !llvm::all_of(R, IsTemplated)) {
+ Diag(R.getNameLoc(), diag::err_non_template_in_template_id)
+ << R.getLookupName();
+ return true;
+ }
+
// During a default argument instantiation the CurContext points
// to a CXXMethodDecl; but we can't apply a this-> fixit inside a
// function parameter list, hence add an explicit check.
@@ -2487,7 +2495,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
R.resolveKind();
}
- return DiagnoseDependentMemberLookup(R);
+ return DiagnoseDependentMemberLookup(R, ExplicitTemplateArgs);
}
R.clear();
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index d304f322aced64..fe9b16e1890c16 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -13860,7 +13860,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
// enclosing class.
// FIXME: We should also explain why the candidates found by name lookup
// were not viable.
- if (SemaRef.DiagnoseDependentMemberLookup(R))
+ if (SemaRef.DiagnoseDependentMemberLookup(R, ExplicitTemplateArgs))
return ExprError();
} else {
// We had viable candidates and couldn't recover; let the caller diagnose
diff --git a/clang/test/SemaTemplate/recovery-crash-cxx20.cpp b/clang/test/SemaTemplate/recovery-crash-cxx20.cpp
new file mode 100644
index 00000000000000..3651b986dfd989
--- /dev/null
+++ b/clang/test/SemaTemplate/recovery-crash-cxx20.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
+
+namespace GH49093 {
+ class B {
+ public:
+ static int a() { return 0; }
+ decltype(a< 0 >(0)) test; // expected-error {{'a' does not name a template but is followed by template arguments}}
+ };
+
+ struct C {
+ static int a() { return 0; }
+ decltype(a < 0 > (0)) test; // expected-error {{'a' does not name a template but is followed by template arguments}}
+ };
+
+ void test_is_bool(bool t) {}
+ void test_is_bool(int t) {}
+
+ int main() {
+ B b;
+ test_is_bool(b.test);
+
+ C c;
+ test_is_bool(c.test);
+ }
+}
+
+namespace GH107047 {
+ struct A {
+ static constexpr auto test() { return 1; }
+ static constexpr int s = test< 1 >(); // expected-error {{'test' does not name a template but is followed by template arguments}}
+ };
+}
>From b9a9758f7f613ffc88cd10da16515558493c27c4 Mon Sep 17 00:00:00 2001
From: Oleksandr T <oleksandr.tarasiuk at outlook.com>
Date: Fri, 27 Sep 2024 15:20:00 +0300
Subject: [PATCH 2/2] use template lookup with typo correction for calls with
explicit arguments
---
clang/include/clang/Sema/Sema.h | 4 +---
clang/lib/Sema/SemaExpr.cpp | 22 +++++++++----------
clang/lib/Sema/SemaOverload.cpp | 2 +-
.../SemaTemplate/recovery-crash-cxx20.cpp | 12 +++++-----
4 files changed, 19 insertions(+), 21 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index b2eefdbd1c56d1..e1c3a99cfa167e 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6753,9 +6753,7 @@ class Sema final : public SemaBase {
///
/// Return \c true if the error is unrecoverable, or \c false if the caller
/// should attempt to recover using these lookup results.
- bool DiagnoseDependentMemberLookup(
- const LookupResult &R,
- TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr);
+ bool DiagnoseDependentMemberLookup(const LookupResult &R);
/// Diagnose an empty lookup.
///
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index a5770ae8848517..271a3534ffb071 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2385,15 +2385,7 @@ static void emitEmptyLookupTypoDiagnostic(
SemaRef.PDiag(NoteID));
}
-bool Sema::DiagnoseDependentMemberLookup(
- const LookupResult &R, TemplateArgumentListInfo *ExplicitTemplateArgs) {
- auto IsTemplated = [](NamedDecl *D) { return D->isTemplated(); };
- if (ExplicitTemplateArgs && !llvm::all_of(R, IsTemplated)) {
- Diag(R.getNameLoc(), diag::err_non_template_in_template_id)
- << R.getLookupName();
- return true;
- }
-
+bool Sema::DiagnoseDependentMemberLookup(const LookupResult &R) {
// During a default argument instantiation the CurContext points
// to a CXXMethodDecl; but we can't apply a this-> fixit inside a
// function parameter list, hence add an explicit check.
@@ -2476,7 +2468,15 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
LookupCtx ? LookupCtx : (SS.isEmpty() ? CurContext : nullptr);
while (DC) {
if (isa<CXXRecordDecl>(DC)) {
- LookupQualifiedName(R, DC);
+ if (ExplicitTemplateArgs) {
+ if (LookupTemplateName(
+ R, S, SS, Context.getRecordType(cast<CXXRecordDecl>(DC)),
+ /*EnteringContext*/ false, TemplateNameIsRequired,
+ /*RequiredTemplateKind*/ nullptr, /*AllowTypoCorrection*/ true))
+ return true;
+ } else {
+ LookupQualifiedName(R, DC);
+ }
if (!R.empty()) {
// Don't give errors about ambiguities in this lookup.
@@ -2495,7 +2495,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
R.resolveKind();
}
- return DiagnoseDependentMemberLookup(R, ExplicitTemplateArgs);
+ return DiagnoseDependentMemberLookup(R);
}
R.clear();
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index db7373e9de0c9c..0c1e054f7c30a4 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -13837,7 +13837,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
// enclosing class.
// FIXME: We should also explain why the candidates found by name lookup
// were not viable.
- if (SemaRef.DiagnoseDependentMemberLookup(R, ExplicitTemplateArgs))
+ if (SemaRef.DiagnoseDependentMemberLookup(R))
return ExprError();
} else {
// We had viable candidates and couldn't recover; let the caller diagnose
diff --git a/clang/test/SemaTemplate/recovery-crash-cxx20.cpp b/clang/test/SemaTemplate/recovery-crash-cxx20.cpp
index 3651b986dfd989..e092ab802e459e 100644
--- a/clang/test/SemaTemplate/recovery-crash-cxx20.cpp
+++ b/clang/test/SemaTemplate/recovery-crash-cxx20.cpp
@@ -3,13 +3,13 @@
namespace GH49093 {
class B {
public:
- static int a() { return 0; }
- decltype(a< 0 >(0)) test; // expected-error {{'a' does not name a template but is followed by template arguments}}
+ static int a() { return 0; } // expected-note {{declared as a non-template here}}
+ decltype(a< 0 >(0)) test; // expected-error {{'a' does not refer to a template}}
};
struct C {
- static int a() { return 0; }
- decltype(a < 0 > (0)) test; // expected-error {{'a' does not name a template but is followed by template arguments}}
+ static int a() { return 0; } // expected-note {{declared as a non-template here}}
+ decltype(a < 0 > (0)) test; // expected-error {{'a' does not refer to a template}}
};
void test_is_bool(bool t) {}
@@ -26,7 +26,7 @@ namespace GH49093 {
namespace GH107047 {
struct A {
- static constexpr auto test() { return 1; }
- static constexpr int s = test< 1 >(); // expected-error {{'test' does not name a template but is followed by template arguments}}
+ static constexpr auto test() { return 1; } // expected-note {{declared as a non-template here}}
+ static constexpr int s = test< 1 >(); // expected-error {{'test' does not refer to a template}}
};
}
More information about the cfe-commits
mailing list