[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-08-12 Thread Daniel M. Katz via cfe-commits

katzdm wrote:

> > > LGTM, but please add a release note so users know about the fix.
> > 
> > 
> > @AaronBallman Appreciate the reminder! Done.
> 
> Thanks! Do you need someone to land the changes?

Yep, I don't have commit privilege - would appreciate the help :)

https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-08-12 Thread Daniel M. Katz via cfe-commits

katzdm wrote:

> LGTM, but please add a release note so users know about the fix.

@AaronBallman Appreciate the reminder! Done.

https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-08-12 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/98671

>From 1ad95178817e58dd7767f0c8b472ec0b7e46cd45 Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Fri, 12 Jul 2024 13:57:33 -0400
Subject: [PATCH 1/5] Fix assertion failure during operator overload
 resolution.

---
 clang/lib/Sema/SemaConcept.cpp |  3 ++-
 clang/test/SemaCXX/PR98671.cpp | 14 ++
 2 files changed, 16 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/SemaCXX/PR98671.cpp

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index de24bbe7eb99ce..ef531fc61dc7c9 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1743,7 +1743,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_FunctionTemplate;
+ Kind == FunctionDecl::TK_FunctionTemplate ||
+ Kind == FunctionDecl::TK_FunctionTemplateSpecialization;
 };
 const auto *FD2 = dyn_cast(D2);
 (void)IsExpectedEntity;
diff --git a/clang/test/SemaCXX/PR98671.cpp b/clang/test/SemaCXX/PR98671.cpp
new file mode 100644
index 00..696b750759854a
--- /dev/null
+++ b/clang/test/SemaCXX/PR98671.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only %s -verify
+
+struct S {
+  operator int();
+
+  template 
+  operator T();
+};
+
+
+// Ensure that no assertion is raised when overload resolution fails while
+// choosing between an operator function template and an operator function.
+constexpr auto r = &S::operator int;
+// expected-error@-1 {{initializer of type ''}}

>From 6c8a48b656d4a0cb8a859a2335e3467467da06aa Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Tue, 16 Jul 2024 11:15:27 -0400
Subject: [PATCH 2/5] Address feedback.

---
 clang/lib/Sema/SemaConcept.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index ef531fc61dc7c9..6f642fabe88359 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1743,7 +1743,7 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_FunctionTemplate ||
+ Kind == FunctionDecl::TK_MemberSpecialization ||
  Kind == FunctionDecl::TK_FunctionTemplateSpecialization;
 };
 const auto *FD2 = dyn_cast(D2);

>From ed648686c56f13dfccc56e50b0cbbb309a2f482e Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Mon, 22 Jul 2024 06:56:53 -0400
Subject: [PATCH 3/5] Change approach to fixing this.

---
 clang/lib/Sema/SemaConcept.cpp   |  3 +--
 clang/lib/Sema/SemaTemplateDeduction.cpp | 23 +--
 clang/test/SemaCXX/PR98671.cpp   | 18 --
 3 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 6f642fabe88359..de24bbe7eb99ce 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1743,8 +1743,7 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_MemberSpecialization ||
- Kind == FunctionDecl::TK_FunctionTemplateSpecialization;
+ Kind == FunctionDecl::TK_FunctionTemplate;
 };
 const auto *FD2 = dyn_cast(D2);
 (void)IsExpectedEntity;
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index e9705ec43d86cc..814d7e3f1f0099 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5805,12 +5805,23 @@ FunctionDecl 
*Sema::getMoreConstrainedFunction(FunctionDecl *FD1,
FunctionDecl *FD2) {
   assert(!FD1->getDescribedTemplate() && !FD2->getDescribedTemplate() &&
  "not for function templates");
-  FunctionDecl *F1 = FD1;
-  if (FunctionDecl *MF = FD1->getInstantiatedFromMemberFunction())
-F1 = MF;
-  FunctionDecl *F2 = FD2;
-  if (FunctionDecl *MF = FD2->getInstantiatedFromMemberFunction())
-F2 = MF;
+
+  auto getTemplatePattern = [](FunctionDecl *FD) {
+// Specializations of conversion function templates are believed to be the
+// only case where a function template specialization reaches here.
+assert(!FD->isFunctionTemplateSpecialization() ||
+   isa(FD));
+
+if (FunctionDecl *MF = FD->getInstantiatedFromMemberFunction())
+  return MF;
+else if (FunctionTemplateDecl *FTD = FD->getPrim

[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-08-12 Thread Daniel M. Katz via cfe-commits

katzdm wrote:

@AaronBallman @cor3ntin Would you mind taking another look?

https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-07-31 Thread Daniel M. Katz via cfe-commits

katzdm wrote:

@zygoloid Friendly ping here, if you have a chance to take another look.

https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-07-25 Thread Daniel M. Katz via cfe-commits


@@ -5824,12 +5824,23 @@ FunctionDecl 
*Sema::getMoreConstrainedFunction(FunctionDecl *FD1,
FunctionDecl *FD2) {
   assert(!FD1->getDescribedTemplate() && !FD2->getDescribedTemplate() &&
  "not for function templates");
-  FunctionDecl *F1 = FD1;
-  if (FunctionDecl *MF = FD1->getInstantiatedFromMemberFunction())
-F1 = MF;
-  FunctionDecl *F2 = FD2;
-  if (FunctionDecl *MF = FD2->getInstantiatedFromMemberFunction())
-F2 = MF;
+
+  auto getTemplatePattern = [](FunctionDecl *FD) {
+// Specializations of conversion function templates are believed to be the
+// only case where a function template specialization reaches here.
+assert(!FD->isFunctionTemplateSpecialization() ||
+   isa(FD));
+
+if (FunctionDecl *MF = FD->getInstantiatedFromMemberFunction())
+  return MF;
+else if (FunctionTemplateDecl *FTD = FD->getPrimaryTemplate())
+  return FTD->getTemplatedDecl();
+
+return FD;
+  };
+  FunctionDecl *F1 = getTemplatePattern(FD1);
+  FunctionDecl *F2 = getTemplatePattern(FD2);

katzdm wrote:

Yes, thank you! Didn't know about that one.

https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-07-25 Thread Daniel M. Katz via cfe-commits


@@ -5824,12 +5824,23 @@ FunctionDecl 
*Sema::getMoreConstrainedFunction(FunctionDecl *FD1,
FunctionDecl *FD2) {
   assert(!FD1->getDescribedTemplate() && !FD2->getDescribedTemplate() &&
  "not for function templates");
-  FunctionDecl *F1 = FD1;
-  if (FunctionDecl *MF = FD1->getInstantiatedFromMemberFunction())
-F1 = MF;
-  FunctionDecl *F2 = FD2;
-  if (FunctionDecl *MF = FD2->getInstantiatedFromMemberFunction())
-F2 = MF;
+
+  auto getTemplatePattern = [](FunctionDecl *FD) {
+// Specializations of conversion function templates are believed to be the
+// only case where a function template specialization reaches here.
+assert(!FD->isFunctionTemplateSpecialization() ||
+   isa(FD));
+
+if (FunctionDecl *MF = FD->getInstantiatedFromMemberFunction())
+  return MF;
+else if (FunctionTemplateDecl *FTD = FD->getPrimaryTemplate())
+  return FTD->getTemplatedDecl();
+
+return FD;
+  };
+  FunctionDecl *F1 = getTemplatePattern(FD1);
+  FunctionDecl *F2 = getTemplatePattern(FD2);

katzdm wrote:

Done.

https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-07-25 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/98671

>From 47db72077258ebe086059f116bbf7fb32c184c8d Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Fri, 12 Jul 2024 13:57:33 -0400
Subject: [PATCH 1/4] Fix assertion failure during operator overload
 resolution.

---
 clang/lib/Sema/SemaConcept.cpp |  3 ++-
 clang/test/SemaCXX/PR98671.cpp | 14 ++
 2 files changed, 16 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/SemaCXX/PR98671.cpp

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 202dd86c67f62..f94fb8be20e07 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1519,7 +1519,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_FunctionTemplate;
+ Kind == FunctionDecl::TK_FunctionTemplate ||
+ Kind == FunctionDecl::TK_FunctionTemplateSpecialization;
 };
 const auto *FD2 = dyn_cast(D2);
 (void)IsExpectedEntity;
diff --git a/clang/test/SemaCXX/PR98671.cpp b/clang/test/SemaCXX/PR98671.cpp
new file mode 100644
index 0..696b750759854
--- /dev/null
+++ b/clang/test/SemaCXX/PR98671.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only %s -verify
+
+struct S {
+  operator int();
+
+  template 
+  operator T();
+};
+
+
+// Ensure that no assertion is raised when overload resolution fails while
+// choosing between an operator function template and an operator function.
+constexpr auto r = &S::operator int;
+// expected-error@-1 {{initializer of type ''}}

>From aa4d40bca37edd0c4facff609b483a6c9994d0c2 Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Tue, 16 Jul 2024 11:15:27 -0400
Subject: [PATCH 2/4] Address feedback.

---
 clang/lib/Sema/SemaConcept.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index f94fb8be20e07..d55a053babaf9 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1519,7 +1519,7 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_FunctionTemplate ||
+ Kind == FunctionDecl::TK_MemberSpecialization ||
  Kind == FunctionDecl::TK_FunctionTemplateSpecialization;
 };
 const auto *FD2 = dyn_cast(D2);

>From adf2226bb95bd71c7d8632b7fe89de8dab57e784 Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Mon, 22 Jul 2024 06:56:53 -0400
Subject: [PATCH 3/4] Change approach to fixing this.

---
 clang/lib/Sema/SemaConcept.cpp   |  3 +--
 clang/lib/Sema/SemaTemplateDeduction.cpp | 23 +--
 clang/test/SemaCXX/PR98671.cpp   | 18 --
 3 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index d55a053babaf9..202dd86c67f62 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1519,8 +1519,7 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_MemberSpecialization ||
- Kind == FunctionDecl::TK_FunctionTemplateSpecialization;
+ Kind == FunctionDecl::TK_FunctionTemplate;
 };
 const auto *FD2 = dyn_cast(D2);
 (void)IsExpectedEntity;
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index b7b857ebf804b..c05909dd09ab8 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5824,12 +5824,23 @@ FunctionDecl 
*Sema::getMoreConstrainedFunction(FunctionDecl *FD1,
FunctionDecl *FD2) {
   assert(!FD1->getDescribedTemplate() && !FD2->getDescribedTemplate() &&
  "not for function templates");
-  FunctionDecl *F1 = FD1;
-  if (FunctionDecl *MF = FD1->getInstantiatedFromMemberFunction())
-F1 = MF;
-  FunctionDecl *F2 = FD2;
-  if (FunctionDecl *MF = FD2->getInstantiatedFromMemberFunction())
-F2 = MF;
+
+  auto getTemplatePattern = [](FunctionDecl *FD) {
+// Specializations of conversion function templates are believed to be the
+// only case where a function template specialization reaches here.
+assert(!FD->isFunctionTemplateSpecialization() ||
+   isa(FD));
+
+if (FunctionDecl *MF = FD->getInstantiatedFromMemberFunction())
+  return MF;
+else if (FunctionTemplateDecl *FTD = FD->getPrimaryTemplat

[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-07-22 Thread Daniel M. Katz via cfe-commits

katzdm wrote:

Looking further into this, I think this is a narrow problem that arises when 
selecting a function from an overload set which includes a specialization of a 
conversion function template.

Consider a class:
```cpp
struct S {
  template  void fn();
  template  operator T();
};
```

When looking up `&S::fn`, the associated `LookupResult` will be a 
singleton containing the `FunctionTemplateDecl` for `fn`, _not_ the function 
template specialization `fn`. The `AddressOfFunctionResolver` in 
`SemaOverload.cpp` will then call 
`Sema::ResolveSingleFunctionTemplateSpecialization`, which will use template 
argument deduction machinery to instantiate `fn`.

Looking up `&S::operator int`, however, is something stranger: Because there 
are no apparent template-arguments, the specialization is resolved [during 
lookup](https://github.com/llvm/llvm-project/blob/main/clang/lib/Sema/SemaLookup.cpp#L1174-L1207)
 instead of afterwards. This is necessary because the information needed to 
select the specialization is encoded in the unqualified-id itself, rather than 
in names and expressions that are parsed thereafter. From what I've been able 
to tell, this situation seems unique to conversion-function-templates, and I 
haven't found other cases where the `LookupResult` directly contains a function 
template specialization.

>From here, deducing the placeholder type for `auto r = &S::operator int;` uses 
>[`Sema::resolveAddressOfSingleOverloadCandidate`](https://github.com/llvm/llvm-project/blob/5b8479bc28a8641f02be3d64f87770b9e0b1a427/clang/lib/Sema/SemaOverload.cpp#L13208-L13291)
> to try to narrow to a single candidate. In the presence of constraints, this 
>calls 
>[`Sema::getMoreConstrainedFunction`](https://github.com/llvm/llvm-project/blob/5b8479bc28a8641f02be3d64f87770b9e0b1a427/clang/lib/Sema/SemaOverload.cpp#L13285)
> to select a "best viable function."

The implementation of `Sema::getMoreConstrainedFunction` 
[already](https://github.com/llvm/llvm-project/blob/5b8479bc28a8641f02be3d64f87770b9e0b1a427/clang/lib/Sema/SemaTemplateDeduction.cpp#L5828-L5832)
 attempts to map instantiated member-functions back to their "pattern 
declarations" (which will have type `TK_FunctionTemplate`) before calling 
`Sema::IsAtLeastAsConstrained`. This handles cases like:

```cpp
template 
struct S {
  void fn();
};
```

but not our conversion-function-template. Since I believe that specializations 
of conversion-function-templates are the only specializations that can appear 
in the `LookupResult`, I suggest a narrow carve-out to handle this case, and an 
assertion to alert us if there are any other such cases which we aren't aware 
of. All tests seem to pass.

https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-07-22 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/98671

>From 47db72077258ebe086059f116bbf7fb32c184c8d Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Fri, 12 Jul 2024 13:57:33 -0400
Subject: [PATCH 1/3] Fix assertion failure during operator overload
 resolution.

---
 clang/lib/Sema/SemaConcept.cpp |  3 ++-
 clang/test/SemaCXX/PR98671.cpp | 14 ++
 2 files changed, 16 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/SemaCXX/PR98671.cpp

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 202dd86c67f62..f94fb8be20e07 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1519,7 +1519,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_FunctionTemplate;
+ Kind == FunctionDecl::TK_FunctionTemplate ||
+ Kind == FunctionDecl::TK_FunctionTemplateSpecialization;
 };
 const auto *FD2 = dyn_cast(D2);
 (void)IsExpectedEntity;
diff --git a/clang/test/SemaCXX/PR98671.cpp b/clang/test/SemaCXX/PR98671.cpp
new file mode 100644
index 0..696b750759854
--- /dev/null
+++ b/clang/test/SemaCXX/PR98671.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only %s -verify
+
+struct S {
+  operator int();
+
+  template 
+  operator T();
+};
+
+
+// Ensure that no assertion is raised when overload resolution fails while
+// choosing between an operator function template and an operator function.
+constexpr auto r = &S::operator int;
+// expected-error@-1 {{initializer of type ''}}

>From aa4d40bca37edd0c4facff609b483a6c9994d0c2 Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Tue, 16 Jul 2024 11:15:27 -0400
Subject: [PATCH 2/3] Address feedback.

---
 clang/lib/Sema/SemaConcept.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index f94fb8be20e07..d55a053babaf9 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1519,7 +1519,7 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_FunctionTemplate ||
+ Kind == FunctionDecl::TK_MemberSpecialization ||
  Kind == FunctionDecl::TK_FunctionTemplateSpecialization;
 };
 const auto *FD2 = dyn_cast(D2);

>From adf2226bb95bd71c7d8632b7fe89de8dab57e784 Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Mon, 22 Jul 2024 06:56:53 -0400
Subject: [PATCH 3/3] Change approach to fixing this.

---
 clang/lib/Sema/SemaConcept.cpp   |  3 +--
 clang/lib/Sema/SemaTemplateDeduction.cpp | 23 +--
 clang/test/SemaCXX/PR98671.cpp   | 18 --
 3 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index d55a053babaf9..202dd86c67f62 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1519,8 +1519,7 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_MemberSpecialization ||
- Kind == FunctionDecl::TK_FunctionTemplateSpecialization;
+ Kind == FunctionDecl::TK_FunctionTemplate;
 };
 const auto *FD2 = dyn_cast(D2);
 (void)IsExpectedEntity;
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index b7b857ebf804b..c05909dd09ab8 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5824,12 +5824,23 @@ FunctionDecl 
*Sema::getMoreConstrainedFunction(FunctionDecl *FD1,
FunctionDecl *FD2) {
   assert(!FD1->getDescribedTemplate() && !FD2->getDescribedTemplate() &&
  "not for function templates");
-  FunctionDecl *F1 = FD1;
-  if (FunctionDecl *MF = FD1->getInstantiatedFromMemberFunction())
-F1 = MF;
-  FunctionDecl *F2 = FD2;
-  if (FunctionDecl *MF = FD2->getInstantiatedFromMemberFunction())
-F2 = MF;
+
+  auto getTemplatePattern = [](FunctionDecl *FD) {
+// Specializations of conversion function templates are believed to be the
+// only case where a function template specialization reaches here.
+assert(!FD->isFunctionTemplateSpecialization() ||
+   isa(FD));
+
+if (FunctionDecl *MF = FD->getInstantiatedFromMemberFunction())
+  return MF;
+else if (FunctionTemplateDecl *FTD = FD->getPrimaryTemplat

[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-07-19 Thread Daniel M. Katz via cfe-commits


@@ -1519,7 +1519,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_FunctionTemplate;

katzdm wrote:

Actually, there might be some deeper issues; will follow up off-thread.

https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-07-19 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm edited https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-07-19 Thread Daniel M. Katz via cfe-commits


@@ -1519,7 +1519,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_FunctionTemplate;

katzdm wrote:

@shafik Thanks for taking a look here!

I was able reverse engineer the following program which fails the assertion in 
question, due to removal of `TK_FunctionTemplate` from the list of "expected" 
Decls:

```cpp
template 
struct S {
  template 
S(U={}) requires (^T != ^void) {}

  template 
S(U={}) requires (^T != ^bool) {}
};


S s;
```

@cor3ntin As per your original comment, I think this _does_ imply that the 
assertion is somewhat vacuous - it covers every non-dependent case (well, I 
guess the `TK_FunctionTemplate` case is sort of dependent too, but whatever).

Would it be better just to remove this assertion altogether, and perhaps to add 
the above snippet as a test for future reference? Let me know what y'all think 
would be best.

https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-07-19 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm deleted 
https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-07-19 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm edited https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-07-19 Thread Daniel M. Katz via cfe-commits


@@ -1519,7 +1519,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_FunctionTemplate;

katzdm wrote:

@shafik Thanks for taking a look here.

@chaoren Looking at this a bit more closely, I think the suggested removal of 
`TK_FunctionTemplate` may be incorrect. The affected 
`Sema::IsAtLeastAsConstrained` function is leveraged by three functions in 
`SemaTemplateDeduction.cpp`:
- `Sema::getMoreSpecializedTemplate`
- `Sema::getMoreConstrainedFunction`
- `Sema::getMoreSpecialized`

The first of these, `Sema::getMoreSpecializedTemplate`, checks the 
"constrained-ness" of the templated `FunctionDecl`s associated with two 
`FunctionTemplateDecl`s. I believe the removed `TK_FunctionTemplate` case would 
apply here. I'll work backwards from there to see if I can produce a failing 
test case.

https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-07-16 Thread Daniel M. Katz via cfe-commits


@@ -1519,7 +1519,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_FunctionTemplate;
+ Kind == FunctionDecl::TK_FunctionTemplate ||

katzdm wrote:

Seems right - Done; tests still seem to pass.

https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-07-16 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/98671

>From 47db72077258ebe086059f116bbf7fb32c184c8d Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Fri, 12 Jul 2024 13:57:33 -0400
Subject: [PATCH 1/2] Fix assertion failure during operator overload
 resolution.

---
 clang/lib/Sema/SemaConcept.cpp |  3 ++-
 clang/test/SemaCXX/PR98671.cpp | 14 ++
 2 files changed, 16 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/SemaCXX/PR98671.cpp

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 202dd86c67f62..f94fb8be20e07 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1519,7 +1519,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_FunctionTemplate;
+ Kind == FunctionDecl::TK_FunctionTemplate ||
+ Kind == FunctionDecl::TK_FunctionTemplateSpecialization;
 };
 const auto *FD2 = dyn_cast(D2);
 (void)IsExpectedEntity;
diff --git a/clang/test/SemaCXX/PR98671.cpp b/clang/test/SemaCXX/PR98671.cpp
new file mode 100644
index 0..696b750759854
--- /dev/null
+++ b/clang/test/SemaCXX/PR98671.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only %s -verify
+
+struct S {
+  operator int();
+
+  template 
+  operator T();
+};
+
+
+// Ensure that no assertion is raised when overload resolution fails while
+// choosing between an operator function template and an operator function.
+constexpr auto r = &S::operator int;
+// expected-error@-1 {{initializer of type ''}}

>From aa4d40bca37edd0c4facff609b483a6c9994d0c2 Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Tue, 16 Jul 2024 11:15:27 -0400
Subject: [PATCH 2/2] Address feedback.

---
 clang/lib/Sema/SemaConcept.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index f94fb8be20e07..d55a053babaf9 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1519,7 +1519,7 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_FunctionTemplate ||
+ Kind == FunctionDecl::TK_MemberSpecialization ||
  Kind == FunctionDecl::TK_FunctionTemplateSpecialization;
 };
 const auto *FD2 = dyn_cast(D2);

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during conversion function overload resolution. (PR #98671)

2024-07-12 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm edited https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during operator overload resolution. (PR #98671)

2024-07-12 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm ready_for_review 
https://github.com/llvm/llvm-project/pull/98671
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during operator overload resolution. (PR #98671)

2024-07-12 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/98671

>From 47db72077258ebe086059f116bbf7fb32c184c8d Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Fri, 12 Jul 2024 13:57:33 -0400
Subject: [PATCH] Fix assertion failure during operator overload resolution.

---
 clang/lib/Sema/SemaConcept.cpp |  3 ++-
 clang/test/SemaCXX/PR98671.cpp | 14 ++
 2 files changed, 16 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/SemaCXX/PR98671.cpp

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 202dd86c67f62..f94fb8be20e07 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1519,7 +1519,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_FunctionTemplate;
+ Kind == FunctionDecl::TK_FunctionTemplate ||
+ Kind == FunctionDecl::TK_FunctionTemplateSpecialization;
 };
 const auto *FD2 = dyn_cast(D2);
 (void)IsExpectedEntity;
diff --git a/clang/test/SemaCXX/PR98671.cpp b/clang/test/SemaCXX/PR98671.cpp
new file mode 100644
index 0..696b750759854
--- /dev/null
+++ b/clang/test/SemaCXX/PR98671.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only %s -verify
+
+struct S {
+  operator int();
+
+  template 
+  operator T();
+};
+
+
+// Ensure that no assertion is raised when overload resolution fails while
+// choosing between an operator function template and an operator function.
+constexpr auto r = &S::operator int;
+// expected-error@-1 {{initializer of type ''}}

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix assertion failure during operator overload resolution. (PR #98671)

2024-07-12 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm created 
https://github.com/llvm/llvm-project/pull/98671

When clang is built with assertions, an otherwise silent (and seemingly 
innocuous) assertion failure from `SemaConcept.cpp` is triggered by the 
following program:

```cpp
struct S {
  operator int();
  template  operator T();
};

constexpr auto r = &S::operator int;
```

The function in question compares the "constrained-ness" of `S::operator int` 
and `S::operator T`; the template kind of the former is `TK_NonTemplate`, 
whereas the template kind of the later is `TK_FunctionTemplateSpecialization`. 
The later kind is not "expected" by the function, thus the assertion-failure.

>From 9c15b7828f2aec1cd2ffd61141f1be544e2f1f61 Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Fri, 12 Jul 2024 13:57:33 -0400
Subject: [PATCH] Fix assertion failure during operator overload resolution.

---
 clang/lib/Sema/SemaConcept.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 202dd86c67f62..f94fb8be20e07 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1519,7 +1519,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
 auto IsExpectedEntity = [](const FunctionDecl *FD) {
   FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
   return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_FunctionTemplate;
+ Kind == FunctionDecl::TK_FunctionTemplate ||
+ Kind == FunctionDecl::TK_FunctionTemplateSpecialization;
 };
 const auto *FD2 = dyn_cast(D2);
 (void)IsExpectedEntity;

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Fix P2564 handling of variable initializers (PR #89565)

2024-05-18 Thread Daniel M. Katz via cfe-commits

katzdm wrote:

> @katzdm Does it make sense to file an issue so we don't forget to bring the 
> warning back?

Yep, for sure - I've opened #92656.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Fix P2564 handling of variable initializers (PR #89565)

2024-05-16 Thread Daniel M. Katz via cfe-commits

katzdm wrote:

@Fznamznon  Hmm...my suggested change does seem to break some tests :( But to 
circle back to your original question, I think it's not totally unexpected - a 
broader class of variable initializers are now (correctly afaict) evaluated as 
constant expressions, which could make some warnings marked as "runtime 
behavior" no longer apply. I agree though that the result is unfortunate - 
@erichkeane had pushed back on some other warnings similarly getting swallowed 
during review.

I wonder if we're taking the wrong approach here - we could also leave both of 
these warnings as "runtime only", and separately try to diagnose during 
constant evaluation. If that could work, it might make it easier to e.g., only 
diagnose overflow in a branch of a compile-time conditional if it's actually 
evaluated (which GCC seems to manage to do).

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Fix P2564 handling of variable initializers (PR #89565)

2024-05-16 Thread Daniel M. Katz via cfe-commits

katzdm wrote:

> @katzdm It seems after this a `warn_impcast_integer_precision_constant` 
> warning went missing:
> 
> https://godbolt.org/z/ndsPb44b4
> 
> Is that expected?

We changed [this 
diagnostic](https://github.com/llvm/llvm-project/blob/5ac34358181b21135851979c1c949632be5a9d32/clang/lib/Sema/SemaChecking.cpp#L16532-L16535)
 from a "runtime behavior" to "any time" check, but not [this 
one](https://github.com/llvm/llvm-project/blob/5ac34358181b21135851979c1c949632be5a9d32/clang/lib/Sema/SemaChecking.cpp#L16486-L16490)
 - I'm guessing we don't have any tests to cover the later case.

Seems like we'd probably want to retain this warning, too - I'll throw a change 
together, see if it breaks any other tests, and see what reviewers have to say. 
Thanks for calling this out.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Fix P2564 handling of variable initializers (PR #89565)

2024-05-08 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/89565

>From 218ffb6d5a03c96d46bfecdb4490277809f5b62e Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Tue, 16 Apr 2024 17:14:50 -0400
Subject: [PATCH 1/8] Fix bug with constexpr initialization.

---
 clang/lib/Parse/ParseDecl.cpp | 12 ++-
 clang/test/CXX/expr/expr.const/p6-2a.cpp  |  7 +++
 clang/test/SemaCXX/builtin_vectorelements.cpp |  4 ++--
 clang/test/SemaCXX/cxx2a-consteval.cpp| 20 ---
 clang/unittests/Support/TimeProfilerTest.cpp  |  1 -
 5 files changed, 24 insertions(+), 20 deletions(-)

diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 05ad5ecbfaa0c..d71dfaf20a793 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2552,6 +2552,13 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
   return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
 }
 
+static bool isConstexprVariable(const Decl *D) {
+  if (const VarDecl *Var = dyn_cast_or_null(D))
+return Var->isConstexpr();
+
+  return false;
+}
+
 Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
   // RAII type used to track whether we're inside an initializer.
@@ -2559,9 +2566,12 @@ Decl 
*Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Parser &P;
 Declarator &D;
 Decl *ThisDecl;
+llvm::SaveAndRestore ConstantContext;
 
 InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl)
-: P(P), D(D), ThisDecl(ThisDecl) {
+: P(P), D(D), ThisDecl(ThisDecl),
+  ConstantContext(P.Actions.isConstantEvaluatedOverride,
+  isConstexprVariable(ThisDecl)) {
   if (ThisDecl && P.getLangOpts().CPlusPlus) {
 Scope *S = nullptr;
 if (D.getCXXScopeSpec().isSet()) {
diff --git a/clang/test/CXX/expr/expr.const/p6-2a.cpp 
b/clang/test/CXX/expr/expr.const/p6-2a.cpp
index a937474d53b22..8b940b2ee9fb2 100644
--- a/clang/test/CXX/expr/expr.const/p6-2a.cpp
+++ b/clang/test/CXX/expr/expr.const/p6-2a.cpp
@@ -43,12 +43,11 @@ struct Temporary {
 constexpr Temporary t = {3}; // expected-error {{must have constant 
destruction}} expected-note {{created here}} expected-note {{in call}}
 
 namespace P1073R3 {
-consteval int f() { return 42; } // expected-note 2 {{declared here}}
+consteval int f() { return 42; } // expected-note {{declared here}}
 consteval auto g() { return f; }
 consteval int h(int (*p)() = g()) { return p(); }
 constexpr int r = h();
-constexpr auto e = g();  // expected-error {{call to consteval function 
'P1073R3::g' is not a constant expression}} \
-expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
-expected-note 2 {{pointer to a consteval 
declaration is not a constant expression}}
+constexpr auto e = g();  // expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
+expected-note {{pointer to a consteval declaration 
is not a constant expression}}
 static_assert(r == 42);
 } // namespace P1073R3
diff --git a/clang/test/SemaCXX/builtin_vectorelements.cpp 
b/clang/test/SemaCXX/builtin_vectorelements.cpp
index 59ff09ac72e42..12f2cbe57bd47 100644
--- a/clang/test/SemaCXX/builtin_vectorelements.cpp
+++ b/clang/test/SemaCXX/builtin_vectorelements.cpp
@@ -42,11 +42,11 @@ void test_builtin_vectorelements() {
 #include 
 
 consteval int consteval_elements() { // expected-error {{consteval function 
never produces a constant expression}}
-  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}}  
// expected-note {{cannot determine number of elements for sizeless vectors in 
a constant expression}} // expected-note {{cannot determine number of elements 
for sizeless vectors in a constant expression}}
+  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}} // 
expected-note {{cannot determine number of elements for sizeless vectors in a 
constant expression}}
 }
 
 void test_bad_constexpr() {
-  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-error {{not a constant expression}} // 
expected-note {{in call}} // expected-note {{in call}}
+  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-note {{in call}}
   constexpr int i32 = __builtin_vectorelements(svuint32_t); // expected-error 
{{initialized by a constant expression}} // expected-note {{cannot determine 
number of elements for sizeless vectors in a constant expression}}
   constexpr int i16p8 = __builtin_vectorelements(svuint16_t) + 16; // 
expected-err

[clang] [Clang] Fix P2564 handling of variable initializers (PR #89565)

2024-05-08 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/89565

>From 218ffb6d5a03c96d46bfecdb4490277809f5b62e Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Tue, 16 Apr 2024 17:14:50 -0400
Subject: [PATCH 1/8] Fix bug with constexpr initialization.

---
 clang/lib/Parse/ParseDecl.cpp | 12 ++-
 clang/test/CXX/expr/expr.const/p6-2a.cpp  |  7 +++
 clang/test/SemaCXX/builtin_vectorelements.cpp |  4 ++--
 clang/test/SemaCXX/cxx2a-consteval.cpp| 20 ---
 clang/unittests/Support/TimeProfilerTest.cpp  |  1 -
 5 files changed, 24 insertions(+), 20 deletions(-)

diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 05ad5ecbfaa0c..d71dfaf20a793 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2552,6 +2552,13 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
   return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
 }
 
+static bool isConstexprVariable(const Decl *D) {
+  if (const VarDecl *Var = dyn_cast_or_null(D))
+return Var->isConstexpr();
+
+  return false;
+}
+
 Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
   // RAII type used to track whether we're inside an initializer.
@@ -2559,9 +2566,12 @@ Decl 
*Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Parser &P;
 Declarator &D;
 Decl *ThisDecl;
+llvm::SaveAndRestore ConstantContext;
 
 InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl)
-: P(P), D(D), ThisDecl(ThisDecl) {
+: P(P), D(D), ThisDecl(ThisDecl),
+  ConstantContext(P.Actions.isConstantEvaluatedOverride,
+  isConstexprVariable(ThisDecl)) {
   if (ThisDecl && P.getLangOpts().CPlusPlus) {
 Scope *S = nullptr;
 if (D.getCXXScopeSpec().isSet()) {
diff --git a/clang/test/CXX/expr/expr.const/p6-2a.cpp 
b/clang/test/CXX/expr/expr.const/p6-2a.cpp
index a937474d53b22..8b940b2ee9fb2 100644
--- a/clang/test/CXX/expr/expr.const/p6-2a.cpp
+++ b/clang/test/CXX/expr/expr.const/p6-2a.cpp
@@ -43,12 +43,11 @@ struct Temporary {
 constexpr Temporary t = {3}; // expected-error {{must have constant 
destruction}} expected-note {{created here}} expected-note {{in call}}
 
 namespace P1073R3 {
-consteval int f() { return 42; } // expected-note 2 {{declared here}}
+consteval int f() { return 42; } // expected-note {{declared here}}
 consteval auto g() { return f; }
 consteval int h(int (*p)() = g()) { return p(); }
 constexpr int r = h();
-constexpr auto e = g();  // expected-error {{call to consteval function 
'P1073R3::g' is not a constant expression}} \
-expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
-expected-note 2 {{pointer to a consteval 
declaration is not a constant expression}}
+constexpr auto e = g();  // expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
+expected-note {{pointer to a consteval declaration 
is not a constant expression}}
 static_assert(r == 42);
 } // namespace P1073R3
diff --git a/clang/test/SemaCXX/builtin_vectorelements.cpp 
b/clang/test/SemaCXX/builtin_vectorelements.cpp
index 59ff09ac72e42..12f2cbe57bd47 100644
--- a/clang/test/SemaCXX/builtin_vectorelements.cpp
+++ b/clang/test/SemaCXX/builtin_vectorelements.cpp
@@ -42,11 +42,11 @@ void test_builtin_vectorelements() {
 #include 
 
 consteval int consteval_elements() { // expected-error {{consteval function 
never produces a constant expression}}
-  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}}  
// expected-note {{cannot determine number of elements for sizeless vectors in 
a constant expression}} // expected-note {{cannot determine number of elements 
for sizeless vectors in a constant expression}}
+  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}} // 
expected-note {{cannot determine number of elements for sizeless vectors in a 
constant expression}}
 }
 
 void test_bad_constexpr() {
-  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-error {{not a constant expression}} // 
expected-note {{in call}} // expected-note {{in call}}
+  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-note {{in call}}
   constexpr int i32 = __builtin_vectorelements(svuint32_t); // expected-error 
{{initialized by a constant expression}} // expected-note {{cannot determine 
number of elements for sizeless vectors in a constant expression}}
   constexpr int i16p8 = __builtin_vectorelements(svuint16_t) + 16; // 
expected-err

[clang] Fix P2564 handling of variable initializers (PR #89565)

2024-05-07 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm edited https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-05-06 Thread Daniel M. Katz via cfe-commits

katzdm wrote:

πŸ‘‹ Friendly ping - No worries if more time is needed to consider the impact of 
this one, but wanted to check if any more changes are needed at this time.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-29 Thread Daniel M. Katz via cfe-commits


@@ -16548,11 +16548,10 @@ static void CheckImplicitConversion(Sema &S, Expr *E, 
QualType T,
 std::string PrettySourceValue = toString(Value, 10);
 std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);
 
-S.DiagRuntimeBehavior(
-E->getExprLoc(), E,
-S.PDiag(diag::warn_impcast_integer_precision_constant)
-<< PrettySourceValue << PrettyTargetValue << E->getType() << T
-<< E->getSourceRange() << SourceRange(CC));

katzdm wrote:

@cor3ntin Do you think any changes to diagnostics need to happen in this PR, or 
are you okay with the warning applying during constant evaluation?

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-29 Thread Daniel M. Katz via cfe-commits


@@ -18573,25 +18562,35 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, 
Decl *D) {
   if (S && D->isOutOfLine())
 EnterDeclaratorContext(S, D->getDeclContext());
 
-  // If we are parsing the initializer for a static data member, push a
-  // new expression evaluation context that is associated with this static
-  // data member.
-  if (isNonlocalVariable(D))
-PushExpressionEvaluationContext(
-ExpressionEvaluationContext::PotentiallyEvaluated, D);
+  PushExpressionEvaluationContext(
+  ExpressionEvaluationContext::PotentiallyEvaluated, D);
 }
 
 /// Invoked after we are finished parsing an initializer for the declaration D.
 void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
-  // If there is no declaration, there was an error parsing it.
-  if (!D || D->isInvalidDecl())
-return;
-
-  if (isNonlocalVariable(D))
-PopExpressionEvaluationContext();
+  assert(D);
 
   if (S && D->isOutOfLine())
 ExitDeclaratorContext(S);
+
+  if (getLangOpts().CPlusPlus23) {
+// An expression or conversion is 'manifestly constant-evaluated' if it is:
+// [...]
+// - the initializer of a variable that is usable in constant expressions 
or
+//   has constant initialization.
+if (auto *VD = dyn_cast(D);
+VD && (VD->isUsableInConstantExpressions(Context) ||
+   VD->hasConstantInitialization())) {
+  // An expression or conversion is in an 'immediate function context' if 
it
+  // is potentially evaluated and either:
+  // [...]
+  // - it is a subexpression of a manifestly constant-evaluated expression
+  //   or conversion.
+  ExprEvalContexts.back().InImmediateFunctionContext = true;
+}
+  }
+
+  PopExpressionEvaluationContext();

katzdm wrote:

I've added a clarifying comment - let me know if you think it's sufficient.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-29 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/89565

>From 218ffb6d5a03c96d46bfecdb4490277809f5b62e Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Tue, 16 Apr 2024 17:14:50 -0400
Subject: [PATCH 1/8] Fix bug with constexpr initialization.

---
 clang/lib/Parse/ParseDecl.cpp | 12 ++-
 clang/test/CXX/expr/expr.const/p6-2a.cpp  |  7 +++
 clang/test/SemaCXX/builtin_vectorelements.cpp |  4 ++--
 clang/test/SemaCXX/cxx2a-consteval.cpp| 20 ---
 clang/unittests/Support/TimeProfilerTest.cpp  |  1 -
 5 files changed, 24 insertions(+), 20 deletions(-)

diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 05ad5ecbfaa0cf..d71dfaf20a793b 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2552,6 +2552,13 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
   return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
 }
 
+static bool isConstexprVariable(const Decl *D) {
+  if (const VarDecl *Var = dyn_cast_or_null(D))
+return Var->isConstexpr();
+
+  return false;
+}
+
 Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
   // RAII type used to track whether we're inside an initializer.
@@ -2559,9 +2566,12 @@ Decl 
*Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Parser &P;
 Declarator &D;
 Decl *ThisDecl;
+llvm::SaveAndRestore ConstantContext;
 
 InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl)
-: P(P), D(D), ThisDecl(ThisDecl) {
+: P(P), D(D), ThisDecl(ThisDecl),
+  ConstantContext(P.Actions.isConstantEvaluatedOverride,
+  isConstexprVariable(ThisDecl)) {
   if (ThisDecl && P.getLangOpts().CPlusPlus) {
 Scope *S = nullptr;
 if (D.getCXXScopeSpec().isSet()) {
diff --git a/clang/test/CXX/expr/expr.const/p6-2a.cpp 
b/clang/test/CXX/expr/expr.const/p6-2a.cpp
index a937474d53b221..8b940b2ee9fb2a 100644
--- a/clang/test/CXX/expr/expr.const/p6-2a.cpp
+++ b/clang/test/CXX/expr/expr.const/p6-2a.cpp
@@ -43,12 +43,11 @@ struct Temporary {
 constexpr Temporary t = {3}; // expected-error {{must have constant 
destruction}} expected-note {{created here}} expected-note {{in call}}
 
 namespace P1073R3 {
-consteval int f() { return 42; } // expected-note 2 {{declared here}}
+consteval int f() { return 42; } // expected-note {{declared here}}
 consteval auto g() { return f; }
 consteval int h(int (*p)() = g()) { return p(); }
 constexpr int r = h();
-constexpr auto e = g();  // expected-error {{call to consteval function 
'P1073R3::g' is not a constant expression}} \
-expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
-expected-note 2 {{pointer to a consteval 
declaration is not a constant expression}}
+constexpr auto e = g();  // expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
+expected-note {{pointer to a consteval declaration 
is not a constant expression}}
 static_assert(r == 42);
 } // namespace P1073R3
diff --git a/clang/test/SemaCXX/builtin_vectorelements.cpp 
b/clang/test/SemaCXX/builtin_vectorelements.cpp
index 59ff09ac72e42d..12f2cbe57bd47d 100644
--- a/clang/test/SemaCXX/builtin_vectorelements.cpp
+++ b/clang/test/SemaCXX/builtin_vectorelements.cpp
@@ -42,11 +42,11 @@ void test_builtin_vectorelements() {
 #include 
 
 consteval int consteval_elements() { // expected-error {{consteval function 
never produces a constant expression}}
-  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}}  
// expected-note {{cannot determine number of elements for sizeless vectors in 
a constant expression}} // expected-note {{cannot determine number of elements 
for sizeless vectors in a constant expression}}
+  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}} // 
expected-note {{cannot determine number of elements for sizeless vectors in a 
constant expression}}
 }
 
 void test_bad_constexpr() {
-  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-error {{not a constant expression}} // 
expected-note {{in call}} // expected-note {{in call}}
+  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-note {{in call}}
   constexpr int i32 = __builtin_vectorelements(svuint32_t); // expected-error 
{{initialized by a constant expression}} // expected-note {{cannot determine 
number of elements for sizeless vectors in a constant expression}}
   constexpr int i16p8 = __builtin_vectorelements(svuint16_t) + 16; // 
expect

[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-29 Thread Daniel M. Katz via cfe-commits


@@ -16548,11 +16548,10 @@ static void CheckImplicitConversion(Sema &S, Expr *E, 
QualType T,
 std::string PrettySourceValue = toString(Value, 10);
 std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);
 
-S.DiagRuntimeBehavior(
-E->getExprLoc(), E,
-S.PDiag(diag::warn_impcast_integer_precision_constant)
-<< PrettySourceValue << PrettyTargetValue << E->getType() << T
-<< E->getSourceRange() << SourceRange(CC));

katzdm wrote:

I'm fine either way, but the following three warning diagnostics are lost 
without this change:
- 
[CXX/expr/expr.const/p2-0x.cpp#L247](https://github.com/llvm/llvm-project/blob/main/clang/test/CXX/expr/expr.const/p2-0x.cpp#L247)
- 
[CXX/expr/expr.const/p2-0x.cpp$248](https://github.com/llvm/llvm-project/blob/main/clang/test/CXX/expr/expr.const/p2-0x.cpp#L248)
- 
[AST/Interp/intap.cpp#L12](https://github.com/llvm/llvm-project/blob/main/clang/test/AST/Interp/intap.cpp#L12)

I think @erichkeane previously objected to losing these diagnostics.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-29 Thread Daniel M. Katz via cfe-commits


@@ -18573,25 +18562,35 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, 
Decl *D) {
   if (S && D->isOutOfLine())
 EnterDeclaratorContext(S, D->getDeclContext());
 
-  // If we are parsing the initializer for a static data member, push a
-  // new expression evaluation context that is associated with this static
-  // data member.
-  if (isNonlocalVariable(D))
-PushExpressionEvaluationContext(
-ExpressionEvaluationContext::PotentiallyEvaluated, D);
+  PushExpressionEvaluationContext(
+  ExpressionEvaluationContext::PotentiallyEvaluated, D);
 }
 
 /// Invoked after we are finished parsing an initializer for the declaration D.
 void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
-  // If there is no declaration, there was an error parsing it.
-  if (!D || D->isInvalidDecl())
-return;

katzdm wrote:

Responded in comment above.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-29 Thread Daniel M. Katz via cfe-commits


@@ -18562,9 +18553,7 @@ static bool isNonlocalVariable(const Decl *D) {
 /// class X. If the declaration had a scope specifier, a scope will have
 /// been created and passed in for this purpose. Otherwise, S will be null.
 void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
-  // If there is no declaration, there was an error parsing it.
-  if (!D || D->isInvalidDecl())
-return;

katzdm wrote:

Ah, I see how it could look that way; it's not in fact unrelated.

Prior this PR, `InitializerScopeRAII::pop()` was called _before_ attaching the 
initializer to the `VarDecl`. This gave an invariant that if the `VarDecl` was 
valid when the scope was entered, it would continue to be valid when it was 
exited.

With this PR, the `VarDecl` can invalidated when the initializer is attached; 
`D->isInvalidDecl()` might be false when calling 
`ActOnCXXEnterDeclInitializer`, but might be true when calling 
`ActOnCXXExitDeclInitializer`. We therefore can't just no-op in 
`ActOnCXXExitDeclInitializer` when the variable is invalid, or else we'll never 
pop the expression evaluation context (leading to assert-failures from scope 
entity mismatch, etc).

This is what motivates adding an `Entered` field to `InitializerScopeRAII` 
(`false` if `!D` or `D->isInvalidDecl` at scope-entry time) to remember whether 
`ActOnCXXExitDeclInitializer` needs to be called at scope-exit time. So this 
check is still present, but it's been lifted from this callsite to 
`InitializerScopeRAII`; I figured it couldn't hurt to leave some assertions to 
ensure the expected preconditions continue to be met going forward.

Let me know if that seems reasonable, or if there's another way you'd rather 
see this done.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-26 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/89565

>From 218ffb6d5a03c96d46bfecdb4490277809f5b62e Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Tue, 16 Apr 2024 17:14:50 -0400
Subject: [PATCH 1/7] Fix bug with constexpr initialization.

---
 clang/lib/Parse/ParseDecl.cpp | 12 ++-
 clang/test/CXX/expr/expr.const/p6-2a.cpp  |  7 +++
 clang/test/SemaCXX/builtin_vectorelements.cpp |  4 ++--
 clang/test/SemaCXX/cxx2a-consteval.cpp| 20 ---
 clang/unittests/Support/TimeProfilerTest.cpp  |  1 -
 5 files changed, 24 insertions(+), 20 deletions(-)

diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 05ad5ecbfaa0cf..d71dfaf20a793b 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2552,6 +2552,13 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
   return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
 }
 
+static bool isConstexprVariable(const Decl *D) {
+  if (const VarDecl *Var = dyn_cast_or_null(D))
+return Var->isConstexpr();
+
+  return false;
+}
+
 Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
   // RAII type used to track whether we're inside an initializer.
@@ -2559,9 +2566,12 @@ Decl 
*Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Parser &P;
 Declarator &D;
 Decl *ThisDecl;
+llvm::SaveAndRestore ConstantContext;
 
 InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl)
-: P(P), D(D), ThisDecl(ThisDecl) {
+: P(P), D(D), ThisDecl(ThisDecl),
+  ConstantContext(P.Actions.isConstantEvaluatedOverride,
+  isConstexprVariable(ThisDecl)) {
   if (ThisDecl && P.getLangOpts().CPlusPlus) {
 Scope *S = nullptr;
 if (D.getCXXScopeSpec().isSet()) {
diff --git a/clang/test/CXX/expr/expr.const/p6-2a.cpp 
b/clang/test/CXX/expr/expr.const/p6-2a.cpp
index a937474d53b221..8b940b2ee9fb2a 100644
--- a/clang/test/CXX/expr/expr.const/p6-2a.cpp
+++ b/clang/test/CXX/expr/expr.const/p6-2a.cpp
@@ -43,12 +43,11 @@ struct Temporary {
 constexpr Temporary t = {3}; // expected-error {{must have constant 
destruction}} expected-note {{created here}} expected-note {{in call}}
 
 namespace P1073R3 {
-consteval int f() { return 42; } // expected-note 2 {{declared here}}
+consteval int f() { return 42; } // expected-note {{declared here}}
 consteval auto g() { return f; }
 consteval int h(int (*p)() = g()) { return p(); }
 constexpr int r = h();
-constexpr auto e = g();  // expected-error {{call to consteval function 
'P1073R3::g' is not a constant expression}} \
-expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
-expected-note 2 {{pointer to a consteval 
declaration is not a constant expression}}
+constexpr auto e = g();  // expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
+expected-note {{pointer to a consteval declaration 
is not a constant expression}}
 static_assert(r == 42);
 } // namespace P1073R3
diff --git a/clang/test/SemaCXX/builtin_vectorelements.cpp 
b/clang/test/SemaCXX/builtin_vectorelements.cpp
index 59ff09ac72e42d..12f2cbe57bd47d 100644
--- a/clang/test/SemaCXX/builtin_vectorelements.cpp
+++ b/clang/test/SemaCXX/builtin_vectorelements.cpp
@@ -42,11 +42,11 @@ void test_builtin_vectorelements() {
 #include 
 
 consteval int consteval_elements() { // expected-error {{consteval function 
never produces a constant expression}}
-  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}}  
// expected-note {{cannot determine number of elements for sizeless vectors in 
a constant expression}} // expected-note {{cannot determine number of elements 
for sizeless vectors in a constant expression}}
+  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}} // 
expected-note {{cannot determine number of elements for sizeless vectors in a 
constant expression}}
 }
 
 void test_bad_constexpr() {
-  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-error {{not a constant expression}} // 
expected-note {{in call}} // expected-note {{in call}}
+  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-note {{in call}}
   constexpr int i32 = __builtin_vectorelements(svuint32_t); // expected-error 
{{initialized by a constant expression}} // expected-note {{cannot determine 
number of elements for sizeless vectors in a constant expression}}
   constexpr int i16p8 = __builtin_vectorelements(svuint16_t) + 16; // 
expect

[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-26 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm edited https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-26 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/89565

>From 218ffb6d5a03c96d46bfecdb4490277809f5b62e Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Tue, 16 Apr 2024 17:14:50 -0400
Subject: [PATCH 1/7] Fix bug with constexpr initialization.

---
 clang/lib/Parse/ParseDecl.cpp | 12 ++-
 clang/test/CXX/expr/expr.const/p6-2a.cpp  |  7 +++
 clang/test/SemaCXX/builtin_vectorelements.cpp |  4 ++--
 clang/test/SemaCXX/cxx2a-consteval.cpp| 20 ---
 clang/unittests/Support/TimeProfilerTest.cpp  |  1 -
 5 files changed, 24 insertions(+), 20 deletions(-)

diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 05ad5ecbfaa0cf..d71dfaf20a793b 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2552,6 +2552,13 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
   return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
 }
 
+static bool isConstexprVariable(const Decl *D) {
+  if (const VarDecl *Var = dyn_cast_or_null(D))
+return Var->isConstexpr();
+
+  return false;
+}
+
 Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
   // RAII type used to track whether we're inside an initializer.
@@ -2559,9 +2566,12 @@ Decl 
*Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Parser &P;
 Declarator &D;
 Decl *ThisDecl;
+llvm::SaveAndRestore ConstantContext;
 
 InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl)
-: P(P), D(D), ThisDecl(ThisDecl) {
+: P(P), D(D), ThisDecl(ThisDecl),
+  ConstantContext(P.Actions.isConstantEvaluatedOverride,
+  isConstexprVariable(ThisDecl)) {
   if (ThisDecl && P.getLangOpts().CPlusPlus) {
 Scope *S = nullptr;
 if (D.getCXXScopeSpec().isSet()) {
diff --git a/clang/test/CXX/expr/expr.const/p6-2a.cpp 
b/clang/test/CXX/expr/expr.const/p6-2a.cpp
index a937474d53b221..8b940b2ee9fb2a 100644
--- a/clang/test/CXX/expr/expr.const/p6-2a.cpp
+++ b/clang/test/CXX/expr/expr.const/p6-2a.cpp
@@ -43,12 +43,11 @@ struct Temporary {
 constexpr Temporary t = {3}; // expected-error {{must have constant 
destruction}} expected-note {{created here}} expected-note {{in call}}
 
 namespace P1073R3 {
-consteval int f() { return 42; } // expected-note 2 {{declared here}}
+consteval int f() { return 42; } // expected-note {{declared here}}
 consteval auto g() { return f; }
 consteval int h(int (*p)() = g()) { return p(); }
 constexpr int r = h();
-constexpr auto e = g();  // expected-error {{call to consteval function 
'P1073R3::g' is not a constant expression}} \
-expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
-expected-note 2 {{pointer to a consteval 
declaration is not a constant expression}}
+constexpr auto e = g();  // expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
+expected-note {{pointer to a consteval declaration 
is not a constant expression}}
 static_assert(r == 42);
 } // namespace P1073R3
diff --git a/clang/test/SemaCXX/builtin_vectorelements.cpp 
b/clang/test/SemaCXX/builtin_vectorelements.cpp
index 59ff09ac72e42d..12f2cbe57bd47d 100644
--- a/clang/test/SemaCXX/builtin_vectorelements.cpp
+++ b/clang/test/SemaCXX/builtin_vectorelements.cpp
@@ -42,11 +42,11 @@ void test_builtin_vectorelements() {
 #include 
 
 consteval int consteval_elements() { // expected-error {{consteval function 
never produces a constant expression}}
-  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}}  
// expected-note {{cannot determine number of elements for sizeless vectors in 
a constant expression}} // expected-note {{cannot determine number of elements 
for sizeless vectors in a constant expression}}
+  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}} // 
expected-note {{cannot determine number of elements for sizeless vectors in a 
constant expression}}
 }
 
 void test_bad_constexpr() {
-  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-error {{not a constant expression}} // 
expected-note {{in call}} // expected-note {{in call}}
+  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-note {{in call}}
   constexpr int i32 = __builtin_vectorelements(svuint32_t); // expected-error 
{{initialized by a constant expression}} // expected-note {{cannot determine 
number of elements for sizeless vectors in a constant expression}}
   constexpr int i16p8 = __builtin_vectorelements(svuint16_t) + 16; // 
expect

[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-26 Thread Daniel M. Katz via cfe-commits


@@ -1032,17 +1043,15 @@ int f() {
 
 namespace GH57682 {
 void test() {
-  constexpr auto l1 = []() consteval { // expected-error {{cannot take address 
of consteval call operator of '(lambda at}} \
-   // expected-note  2{{declared here}}
+  constexpr auto l1 = []() consteval { // expected-note  {{declared here}}
 return 3;
   };
   constexpr int (*f1)(void) = l1; // expected-error {{constexpr variable 'f1' 
must be initialized by a constant expression}} \
   // expected-note  {{pointer to a consteval 
declaration is not a constant expression}}
 
 
-  constexpr auto lstatic = []() static consteval { // expected-error {{cannot 
take address of consteval call operator of '(lambda at}} \
-   // expected-note  2{{declared here}} \
-   // expected-warning {{extension}}
+  constexpr auto lstatic = []() static consteval { // expected-note  
{{declared here}} \
+   // expected-warning 
{{extension}}

katzdm wrote:

I've added some test cases for assigning to a non constexpr variable, both 
within and outside of an immediate function context.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-26 Thread Daniel M. Katz via cfe-commits


@@ -244,8 +244,8 @@ namespace UndefinedBehavior {
 constexpr int n13 = n5 + n5; // expected-error {{constant expression}} 
expected-note {{value -4294967296 is outside the range of }}
 constexpr int n14 = n3 - n5; // expected-error {{constant expression}} 
expected-note {{value 4294967295 is outside the range of }}
 constexpr int n15 = n5 * n5; // expected-error {{constant expression}} 
expected-note {{value 4611686018427387904 is outside the range of }}
-constexpr signed char c1 = 100 * 2; // ok expected-warning{{changes value}}
-constexpr signed char c2 = '\x64' * '\2'; // also ok  
expected-warning{{changes value}}
+constexpr signed char c1 = 100 * 2; // ok - no error from changing value 
because initializer is constexpr.

katzdm wrote:

I think the additional diagnostic is relatively harmless; I've gone ahead with 
the change I suggested above.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-26 Thread Daniel M. Katz via cfe-commits


@@ -2554,16 +2554,27 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
   return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
 }
 
+static bool isConstexprVariable(const Decl *D) {
+  if (const VarDecl *Var = dyn_cast_if_present(D))
+return Var->isConstexpr();
+
+  return false;
+}
+
 Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
   // RAII type used to track whether we're inside an initializer.
   struct InitializerScopeRAII {
 Parser &P;
 Declarator &D;
 Decl *ThisDecl;
+EnterExpressionEvaluationContext EC;
 
 InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl)
-: P(P), D(D), ThisDecl(ThisDecl) {
+: P(P), D(D), ThisDecl(ThisDecl),
+  EC(P.Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated,
+ ThisDecl, Sema::ExpressionEvaluationContextRecord::EK_Other,
+ isConstexprVariable(ThisDecl)) {

katzdm wrote:

@efriedma-quic Your feedback led to my taking a different approach for this PR; 
please see [this 
comment](https://github.com/llvm/llvm-project/pull/89565#issuecomment-2079917447).

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-26 Thread Daniel M. Katz via cfe-commits

katzdm wrote:

This ended up being a lot more subtle than I expected. My latest push proposes 
a different solution; @cor3ntin and @efriedma-quic -  please let me know your 
thoughts.

This PR turns out to be a bug fix on the implementation of 
[P2564R3](https://wg21.link/p2564r3); as such, it only applies to C++23 and 
later. The core problem is that the definition of a constant-initialized 
variable ([`[expr.const/2]`](https://eel.is/c++draft/expr.const#2)) is 
contingent on whether the initializer can be evaluated as a constant expression:

> A variable or temporary object o is _constant-initialized_ if [...] the 
> full-expression of its initialization is a constant expression when 
> interpreted as a _constant-expression_, [...]

That can't be known until we've finished parsing the initializer, by which time 
we've already added immediate invocations and consteval references to the 
current expression evaluation context. This will have the effect of evaluating 
said invocations as full expressions when the context is popped, even if 
they're subexpressions of a larger constant expression initializer. If, 
however, the variable _is_ constant-initialized, then its initializer is 
[manifestly constant-evaluated](https://eel.is/c++draft/expr.const#20):

> An expression or conversion is _manifestly constant-evaluated_ if it is [...] 
> **the initializer of a variable that is usable in constant expressions or has 
> constant initialization** [...]

which in turn means that any subexpressions naming an immediate function are in 
an [immediate function context](https://eel.is/c++draft/expr.const#16):

> An expression or conversion is in an immediate function context if it is 
> potentially evaluated and either [...] it is a **subexpression of a 
> manifestly constant-evaluated expression** or conversion

and therefore _are not to be considered [immediate 
invocations](https://eel.is/c++draft/expr.const#16) or [immediate-escalating 
expressions](https://eel.is/c++draft/expr.const#17) in the first place_:

> An invocation is an _immediate invocation_ if it is a potentially-evaluated 
> explicit or implicit invocation of an immediate function and **is not in an 
> immediate function context**.

> An expression or conversion is _immediate-escalating_ if **it is not 
> initially in an immediate function context** and [...]


The approach that I'm therefore proposing is:
1. Create a new expression evaluation context for _every_ variable initializer 
(rather than only nonlocal ones).
2. Attach initializers to `VarDecl`s _prior_ to popping the expression 
evaluation context / scope / etc. This sequences the determination of whether 
the initializer is in an immediate function context _before_ any contained 
immediate invocations are evaluated.
3. When popping an expression evaluation context, elide all evaluations of 
constant invocations, and all checks for consteval references, if the context 
is an immediate function context. Note that if it could be ascertained that 
this was an immediate function context at parse-time, we [would never have 
registered](https://github.com/llvm/llvm-project/blob/760910ddb918d77e7632be1678f69909384d69ae/clang/lib/Sema/SemaExpr.cpp#L17799)
 these immediate invocations or consteval references in the first place.

Most of the test changes previously made for this PR are now reverted and 
passing as-is. The only test updates needed are now as follows:
- A few diagnostics in `consteval-cxx2a.cpp` are updated to reflect that it is 
the `consteval tester::tester` constructor, not the more narrow `make_name` 
function call, which fails to be evaluated as a constant expression.
- The reclassification of `warn_impcast_integer_precision_constant` as a 
compile-time diagnostic adds a (somewhat duplicative) warning when attempting 
to define an enum constant using a narrowing conversion. It also, however, 
retains the existing diagnostics which @erichkeane (rightly) objected to being 
lost from an earlier revision of this PR.

Sorry for the long-winded explanation of a relatively small change - the 
language in `[expr.const]` is (at least I find) quite involved, so I figured 
more detail couldn't hurt.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-26 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/89565

>From 218ffb6d5a03c96d46bfecdb4490277809f5b62e Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Tue, 16 Apr 2024 17:14:50 -0400
Subject: [PATCH 1/6] Fix bug with constexpr initialization.

---
 clang/lib/Parse/ParseDecl.cpp | 12 ++-
 clang/test/CXX/expr/expr.const/p6-2a.cpp  |  7 +++
 clang/test/SemaCXX/builtin_vectorelements.cpp |  4 ++--
 clang/test/SemaCXX/cxx2a-consteval.cpp| 20 ---
 clang/unittests/Support/TimeProfilerTest.cpp  |  1 -
 5 files changed, 24 insertions(+), 20 deletions(-)

diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 05ad5ecbfaa0cf..d71dfaf20a793b 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2552,6 +2552,13 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
   return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
 }
 
+static bool isConstexprVariable(const Decl *D) {
+  if (const VarDecl *Var = dyn_cast_or_null(D))
+return Var->isConstexpr();
+
+  return false;
+}
+
 Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
   // RAII type used to track whether we're inside an initializer.
@@ -2559,9 +2566,12 @@ Decl 
*Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Parser &P;
 Declarator &D;
 Decl *ThisDecl;
+llvm::SaveAndRestore ConstantContext;
 
 InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl)
-: P(P), D(D), ThisDecl(ThisDecl) {
+: P(P), D(D), ThisDecl(ThisDecl),
+  ConstantContext(P.Actions.isConstantEvaluatedOverride,
+  isConstexprVariable(ThisDecl)) {
   if (ThisDecl && P.getLangOpts().CPlusPlus) {
 Scope *S = nullptr;
 if (D.getCXXScopeSpec().isSet()) {
diff --git a/clang/test/CXX/expr/expr.const/p6-2a.cpp 
b/clang/test/CXX/expr/expr.const/p6-2a.cpp
index a937474d53b221..8b940b2ee9fb2a 100644
--- a/clang/test/CXX/expr/expr.const/p6-2a.cpp
+++ b/clang/test/CXX/expr/expr.const/p6-2a.cpp
@@ -43,12 +43,11 @@ struct Temporary {
 constexpr Temporary t = {3}; // expected-error {{must have constant 
destruction}} expected-note {{created here}} expected-note {{in call}}
 
 namespace P1073R3 {
-consteval int f() { return 42; } // expected-note 2 {{declared here}}
+consteval int f() { return 42; } // expected-note {{declared here}}
 consteval auto g() { return f; }
 consteval int h(int (*p)() = g()) { return p(); }
 constexpr int r = h();
-constexpr auto e = g();  // expected-error {{call to consteval function 
'P1073R3::g' is not a constant expression}} \
-expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
-expected-note 2 {{pointer to a consteval 
declaration is not a constant expression}}
+constexpr auto e = g();  // expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
+expected-note {{pointer to a consteval declaration 
is not a constant expression}}
 static_assert(r == 42);
 } // namespace P1073R3
diff --git a/clang/test/SemaCXX/builtin_vectorelements.cpp 
b/clang/test/SemaCXX/builtin_vectorelements.cpp
index 59ff09ac72e42d..12f2cbe57bd47d 100644
--- a/clang/test/SemaCXX/builtin_vectorelements.cpp
+++ b/clang/test/SemaCXX/builtin_vectorelements.cpp
@@ -42,11 +42,11 @@ void test_builtin_vectorelements() {
 #include 
 
 consteval int consteval_elements() { // expected-error {{consteval function 
never produces a constant expression}}
-  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}}  
// expected-note {{cannot determine number of elements for sizeless vectors in 
a constant expression}} // expected-note {{cannot determine number of elements 
for sizeless vectors in a constant expression}}
+  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}} // 
expected-note {{cannot determine number of elements for sizeless vectors in a 
constant expression}}
 }
 
 void test_bad_constexpr() {
-  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-error {{not a constant expression}} // 
expected-note {{in call}} // expected-note {{in call}}
+  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-note {{in call}}
   constexpr int i32 = __builtin_vectorelements(svuint32_t); // expected-error 
{{initialized by a constant expression}} // expected-note {{cannot determine 
number of elements for sizeless vectors in a constant expression}}
   constexpr int i16p8 = __builtin_vectorelements(svuint16_t) + 16; // 
expect

[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-23 Thread Daniel M. Katz via cfe-commits


@@ -2554,16 +2554,27 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
   return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
 }
 
+static bool isConstexprVariable(const Decl *D) {
+  if (const VarDecl *Var = dyn_cast_if_present(D))
+return Var->isConstexpr();
+
+  return false;
+}
+
 Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
   // RAII type used to track whether we're inside an initializer.
   struct InitializerScopeRAII {
 Parser &P;
 Declarator &D;
 Decl *ThisDecl;
+EnterExpressionEvaluationContext EC;
 
 InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl)
-: P(P), D(D), ThisDecl(ThisDecl) {
+: P(P), D(D), ThisDecl(ThisDecl),
+  EC(P.Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated,
+ ThisDecl, Sema::ExpressionEvaluationContextRecord::EK_Other,
+ isConstexprVariable(ThisDecl)) {

katzdm wrote:

@efriedma-quic I see your point - we need to handle a broader class of 
variables in this case than just `constexpr`. Let me see what I can do, thanks 
for the feedback.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-23 Thread Daniel M. Katz via cfe-commits


@@ -2554,16 +2554,27 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
   return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
 }
 
+static bool isConstexprVariable(const Decl *D) {
+  if (const VarDecl *Var = dyn_cast_if_present(D))
+return Var->isConstexpr();
+
+  return false;
+}
+
 Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
   // RAII type used to track whether we're inside an initializer.
   struct InitializerScopeRAII {
 Parser &P;
 Declarator &D;
 Decl *ThisDecl;
+EnterExpressionEvaluationContext EC;
 
 InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl)
-: P(P), D(D), ThisDecl(ThisDecl) {
+: P(P), D(D), ThisDecl(ThisDecl),
+  EC(P.Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated,
+ ThisDecl, Sema::ExpressionEvaluationContextRecord::EK_Other,
+ isConstexprVariable(ThisDecl)) {

katzdm wrote:

> if I'm understanding the rule, it's not supposed to be valid.

Agreed; MSVC appears to get this right:
```
(8): error C7595: 'fn': call to immediate function is not a constant 
expression
```

Since `int a` is not usable in a constant expression, its initializer isn't 
manifestly constant-evaluated. Thus only the call to `fn()` is manifestly 
constant-evaluated, so the access to the heap-allocated memory is ill-formed.

...as far as I can tell πŸ˜… 

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-23 Thread Daniel M. Katz via cfe-commits


@@ -244,8 +244,8 @@ namespace UndefinedBehavior {
 constexpr int n13 = n5 + n5; // expected-error {{constant expression}} 
expected-note {{value -4294967296 is outside the range of }}
 constexpr int n14 = n3 - n5; // expected-error {{constant expression}} 
expected-note {{value 4294967295 is outside the range of }}
 constexpr int n15 = n5 * n5; // expected-error {{constant expression}} 
expected-note {{value 4611686018427387904 is outside the range of }}
-constexpr signed char c1 = 100 * 2; // ok expected-warning{{changes value}}
-constexpr signed char c2 = '\x64' * '\2'; // also ok  
expected-warning{{changes value}}
+constexpr signed char c1 = 100 * 2; // ok - no error from changing value 
because initializer is constexpr.

katzdm wrote:

Ah, just noticed - `enum-scoped.cpp` isn't a test that's affected by this 
change as-is. The suggested change adds an additional warning to where there's 
already an error; the declaration
```cpp
enum : signed char { A = 128 };
```

is diagnosed with:
```cpp
test2.cpp:1:26: warning: implicit conversion from 'int' to 'signed char' 
changes value from 128 to -128 [-Wconstant-conversion]
1 | enum : signed char { A = 128 };
  |  ^~~
test2.cpp:1:26: error: enumerator value evaluates to 128, which cannot be 
narrowed to type 'signed char' [-Wc++11-narrowing]
```

Not sure how helpful that additional diagnostic is.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-23 Thread Daniel M. Katz via cfe-commits


@@ -244,8 +244,8 @@ namespace UndefinedBehavior {
 constexpr int n13 = n5 + n5; // expected-error {{constant expression}} 
expected-note {{value -4294967296 is outside the range of }}
 constexpr int n14 = n3 - n5; // expected-error {{constant expression}} 
expected-note {{value 4294967295 is outside the range of }}
 constexpr int n15 = n5 * n5; // expected-error {{constant expression}} 
expected-note {{value 4611686018427387904 is outside the range of }}
-constexpr signed char c1 = 100 * 2; // ok expected-warning{{changes value}}
-constexpr signed char c2 = '\x64' * '\2'; // also ok  
expected-warning{{changes value}}
+constexpr signed char c1 = 100 * 2; // ok - no error from changing value 
because initializer is constexpr.

katzdm wrote:

@erichkeane I think that it isn't, because `100`, `2`, and `100 * 2` are all 
expressions of type `int`. The only sideways thing that happens is the implicit 
conversion from `int` to `signed char` that reinterprets the value as `56`.

Both this diagnostic and the other that you commented on can be recovered by 
changing 
[this](https://github.com/llvm/llvm-project/blob/main/clang/lib/Sema/SemaChecking.cpp#L16543-L16547)
 `Sema::DiagRuntimeBehavior` to `Sema::Diag` instead.

Running this change with `check-clang`, we recover the following diagnostics 
that are currently removed by this PR:
- clang/test/AST/Interp/intap.cpp
- clang/test/CXX/expr/expr.const/p2-0x.cpp
- clang/test/SemaCXX/enum-scoped.cpp
- clang/test/SemaCXX/ext-int.cpp

with no other tests newly failing.

Let me know if you think this change makes sense; I'll push it to the PR and 
revert the changes to the tests mentioned above. Also let me know if it's 
desirable for any of the other diagnostics removed by this PR to be kept; happy 
to dig.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Push immediate function context while transforming lambdas in templates. (PR #89702)

2024-04-23 Thread Daniel M. Katz via cfe-commits

katzdm wrote:

> LGTM, thanks! Will you need me to merge the change for you?

@cor3ntin That would be great, thanks!

https://github.com/llvm/llvm-project/pull/89702
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Push immediate function context while transforming lambdas in templates. (PR #89702)

2024-04-22 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/89702

>From ba1c87956f74248467d2f85c20c2f450eef953bd Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Mon, 22 Apr 2024 22:39:06 -0400
Subject: [PATCH] Push immediate function context while transforming lambdas in
 templates.

---
 clang/docs/ReleaseNotes.rst|  3 +++
 clang/lib/Sema/TreeTransform.h |  2 ++
 clang/test/SemaCXX/cxx2a-consteval.cpp | 20 
 3 files changed, 25 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 45a9a79739a4eb..0efdcac3c4b8e1 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -420,6 +420,9 @@ Bug Fixes in This Version
 - Fixed a regression in CTAD that a friend declaration that befriends itself 
may cause
   incorrect constraint substitution. (#GH86769).
 
+- Fixed bug in which the body of a consteval lambda within a template was not 
parsed as within an
+  immediate function context.
+
 Bug Fixes to Compiler Builtins
 ^^
 
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 284c9173e68ed5..a3ddebb3ca5963 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -14044,6 +14044,8 @@ TreeTransform::TransformLambdaExpr(LambdaExpr 
*E) {
   // FIXME: Sema's lambda-building mechanism expects us to push an expression
   // evaluation context even if we're not transforming the function body.
   getSema().PushExpressionEvaluationContext(
+  E->getCallOperator()->isConsteval() ?
+  Sema::ExpressionEvaluationContext::ImmediateFunctionContext :
   Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
 
   Sema::CodeSynthesisContext C;
diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp 
b/clang/test/SemaCXX/cxx2a-consteval.cpp
index 192621225a543c..e198074372072d 100644
--- a/clang/test/SemaCXX/cxx2a-consteval.cpp
+++ b/clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -260,6 +260,26 @@ int(*test)(int)  = l1;
 
 }
 
+namespace consteval_lambda_in_template {
+struct S {
+int *value;
+constexpr S(int v) : value(new int {v}) {}
+constexpr ~S() { delete value; }
+};
+consteval S fn() { return S(5); }
+
+template 
+void fn2() {
+(void)[]() consteval -> int {
+  return *(fn().value);  // OK, immediate context
+};
+}
+
+void caller() {
+fn2();
+}
+}
+
 namespace std {
 
 template  struct remove_reference { using type = T; };

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Push immediate function context while transforming lambdas in templates. (PR #89702)

2024-04-22 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm created 
https://github.com/llvm/llvm-project/pull/89702

The following program is [accepted](https://godbolt.org/z/oEc34Trh4) by Clang, 
EDG, and MSVC, but rejected by Clang:
```cpp
#include 

consteval auto fn() { return std::vector {1,2,3}; }

template 
void fn2() {
(void)[]() consteval {
  for (auto e : fn()) {}
};
}

void caller() {
fn2();
}
```

The stated diagnostic is:
```cpp
:8:21: error: call to consteval function 'fn' is not a constant 
expression
8 |   for (auto e : fn()) {}
```

The body of the lambda should be evaluated as within an immediate function 
context when the lambda is marked as `consteval`.

>From 1db83800ef13fae454709c8ba4a7b80728c7bcbe Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Mon, 22 Apr 2024 22:39:06 -0400
Subject: [PATCH] Push immediate function context while transforming lambdas in
 templates.

---
 clang/docs/ReleaseNotes.rst|  3 +++
 clang/lib/Sema/TreeTransform.h |  2 ++
 clang/test/SemaCXX/cxx2a-consteval.cpp | 20 
 3 files changed, 25 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 45a9a79739a4eb..0efdcac3c4b8e1 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -420,6 +420,9 @@ Bug Fixes in This Version
 - Fixed a regression in CTAD that a friend declaration that befriends itself 
may cause
   incorrect constraint substitution. (#GH86769).
 
+- Fixed bug in which the body of a consteval lambda within a template was not 
parsed as within an
+  immediate function context.
+
 Bug Fixes to Compiler Builtins
 ^^
 
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 284c9173e68ed5..a3ddebb3ca5963 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -14044,6 +14044,8 @@ TreeTransform::TransformLambdaExpr(LambdaExpr 
*E) {
   // FIXME: Sema's lambda-building mechanism expects us to push an expression
   // evaluation context even if we're not transforming the function body.
   getSema().PushExpressionEvaluationContext(
+  E->getCallOperator()->isConsteval() ?
+  Sema::ExpressionEvaluationContext::ImmediateFunctionContext :
   Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
 
   Sema::CodeSynthesisContext C;
diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp 
b/clang/test/SemaCXX/cxx2a-consteval.cpp
index 192621225a543c..b19e25e26c214c 100644
--- a/clang/test/SemaCXX/cxx2a-consteval.cpp
+++ b/clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -260,6 +260,26 @@ int(*test)(int)  = l1;
 
 }
 
+namespace consteval_dependent_lambda {
+struct S {
+int *value;
+constexpr S(int v) : value(new int {v}) {}
+constexpr ~S() { delete value; }
+};
+consteval S fn() { return S(5); }
+
+template 
+void fn2() {
+(void)[]() consteval -> int {
+  return *(fn().value);  // OK, immediate context
+};
+}
+
+void caller() {
+fn2();
+}
+}
+
 namespace std {
 
 template  struct remove_reference { using type = T; };

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-22 Thread Daniel M. Katz via cfe-commits


@@ -2554,16 +2554,26 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
   return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
 }
 
+static bool isConstexprVariable(const Decl *D) {
+  if (const VarDecl *Var = dyn_cast_or_null(D))

katzdm wrote:

@cor3ntin I take it back - I think this can be null during certain error 
codepaths (I got some crashes in a handful of tests when I changed to 
`dyn_cast`). Going to use `dyn_cast_if_present` instead.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-22 Thread Daniel M. Katz via cfe-commits


@@ -1032,17 +1043,15 @@ int f() {
 
 namespace GH57682 {
 void test() {
-  constexpr auto l1 = []() consteval { // expected-error {{cannot take address 
of consteval call operator of '(lambda at}} \
-   // expected-note  2{{declared here}}
+  constexpr auto l1 = []() consteval { // expected-note  {{declared here}}
 return 3;
   };
   constexpr int (*f1)(void) = l1; // expected-error {{constexpr variable 'f1' 
must be initialized by a constant expression}} \
   // expected-note  {{pointer to a consteval 
declaration is not a constant expression}}
 
 
-  constexpr auto lstatic = []() static consteval { // expected-error {{cannot 
take address of consteval call operator of '(lambda at}} \
-   // expected-note  2{{declared here}} \
-   // expected-warning {{extension}}
+  constexpr auto lstatic = []() static consteval { // expected-note  
{{declared here}} \
+   // expected-warning 
{{extension}}

katzdm wrote:

Not that I can tell; I've added one above which assigns the address of the 
lambda to a non-constexpr variable. The resulting diagnostic points to the `l1` 
declaration - seems like ideally it would also diagnose at the site of the 
initializer, but that appears unrelated to this change.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-22 Thread Daniel M. Katz via cfe-commits


@@ -2554,16 +2554,26 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
   return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
 }
 
+static bool isConstexprVariable(const Decl *D) {
+  if (const VarDecl *Var = dyn_cast_or_null(D))

katzdm wrote:

Ah, good to know re: `*_or_null` being deprecated. Thanks.

I think I originally had this utility in `SemaDeclCXX.cpp`, where I copied its 
structure from a similar 
[`isNonlocalVariable()`](https://github.com/llvm/llvm-project/blob/35b292efc6fc31b884255d7cb46db7d6346c6f46/clang/lib/Sema/SemaDeclCXX.cpp#L18550-L18555)
 function. But I agree, I see no reason why this would be null.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-22 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm commented:

@cor3ntin Thanks for your review; this is ready for another look.

Note that the use of a full `ExpressionEvaluationContext` caused a handful of 
other tests to start failing - in particular, ones that previously expected 
warnings related to changes of value from implicit casts. I verified that these 
warnings are all emitted through `Sema::DiagRuntimeBehavior`, which no-ops when 
in a `ConstantEvaluated` context - so the lack of warning seems expected since 
the initializer is now treated as a constant expression.

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-22 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm edited https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-22 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/89565

>From a3f8a8648e2002273d47d7886b29fb02c728b5b7 Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Tue, 16 Apr 2024 17:14:50 -0400
Subject: [PATCH 1/5] Fix bug with constexpr initialization.

---
 clang/lib/Parse/ParseDecl.cpp | 12 ++-
 clang/test/CXX/expr/expr.const/p6-2a.cpp  |  7 ++--
 clang/test/SemaCXX/builtin_vectorelements.cpp |  4 +--
 clang/test/SemaCXX/cxx2a-consteval.cpp| 32 ---
 clang/unittests/Support/TimeProfilerTest.cpp  |  1 -
 5 files changed, 36 insertions(+), 20 deletions(-)

diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 583232f2d610d0..0ea6fccaa7eb34 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2554,6 +2554,13 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
   return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
 }
 
+static bool isConstexprVariable(const Decl *D) {
+  if (const VarDecl *Var = dyn_cast_or_null(D))
+return Var->isConstexpr();
+
+  return false;
+}
+
 Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
   // RAII type used to track whether we're inside an initializer.
@@ -2561,9 +2568,12 @@ Decl 
*Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Parser &P;
 Declarator &D;
 Decl *ThisDecl;
+llvm::SaveAndRestore ConstantContext;
 
 InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl)
-: P(P), D(D), ThisDecl(ThisDecl) {
+: P(P), D(D), ThisDecl(ThisDecl),
+  ConstantContext(P.Actions.isConstantEvaluatedOverride,
+  isConstexprVariable(ThisDecl)) {
   if (ThisDecl && P.getLangOpts().CPlusPlus) {
 Scope *S = nullptr;
 if (D.getCXXScopeSpec().isSet()) {
diff --git a/clang/test/CXX/expr/expr.const/p6-2a.cpp 
b/clang/test/CXX/expr/expr.const/p6-2a.cpp
index a937474d53b221..8b940b2ee9fb2a 100644
--- a/clang/test/CXX/expr/expr.const/p6-2a.cpp
+++ b/clang/test/CXX/expr/expr.const/p6-2a.cpp
@@ -43,12 +43,11 @@ struct Temporary {
 constexpr Temporary t = {3}; // expected-error {{must have constant 
destruction}} expected-note {{created here}} expected-note {{in call}}
 
 namespace P1073R3 {
-consteval int f() { return 42; } // expected-note 2 {{declared here}}
+consteval int f() { return 42; } // expected-note {{declared here}}
 consteval auto g() { return f; }
 consteval int h(int (*p)() = g()) { return p(); }
 constexpr int r = h();
-constexpr auto e = g();  // expected-error {{call to consteval function 
'P1073R3::g' is not a constant expression}} \
-expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
-expected-note 2 {{pointer to a consteval 
declaration is not a constant expression}}
+constexpr auto e = g();  // expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
+expected-note {{pointer to a consteval declaration 
is not a constant expression}}
 static_assert(r == 42);
 } // namespace P1073R3
diff --git a/clang/test/SemaCXX/builtin_vectorelements.cpp 
b/clang/test/SemaCXX/builtin_vectorelements.cpp
index 59ff09ac72e42d..12f2cbe57bd47d 100644
--- a/clang/test/SemaCXX/builtin_vectorelements.cpp
+++ b/clang/test/SemaCXX/builtin_vectorelements.cpp
@@ -42,11 +42,11 @@ void test_builtin_vectorelements() {
 #include 
 
 consteval int consteval_elements() { // expected-error {{consteval function 
never produces a constant expression}}
-  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}}  
// expected-note {{cannot determine number of elements for sizeless vectors in 
a constant expression}} // expected-note {{cannot determine number of elements 
for sizeless vectors in a constant expression}}
+  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}} // 
expected-note {{cannot determine number of elements for sizeless vectors in a 
constant expression}}
 }
 
 void test_bad_constexpr() {
-  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-error {{not a constant expression}} // 
expected-note {{in call}} // expected-note {{in call}}
+  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-note {{in call}}
   constexpr int i32 = __builtin_vectorelements(svuint32_t); // expected-error 
{{initialized by a constant expression}} // expected-note {{cannot determine 
number of elements for sizeless vectors in a constant expression}}
   constexpr int i16p8 = __builtin_vectorelements(svuint16_t) + 16; // 
expected-error

[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-22 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/89565

>From a3f8a8648e2002273d47d7886b29fb02c728b5b7 Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Tue, 16 Apr 2024 17:14:50 -0400
Subject: [PATCH 1/2] Fix bug with constexpr initialization.

---
 clang/lib/Parse/ParseDecl.cpp | 12 ++-
 clang/test/CXX/expr/expr.const/p6-2a.cpp  |  7 ++--
 clang/test/SemaCXX/builtin_vectorelements.cpp |  4 +--
 clang/test/SemaCXX/cxx2a-consteval.cpp| 32 ---
 clang/unittests/Support/TimeProfilerTest.cpp  |  1 -
 5 files changed, 36 insertions(+), 20 deletions(-)

diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 583232f2d610d0..0ea6fccaa7eb34 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2554,6 +2554,13 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
   return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
 }
 
+static bool isConstexprVariable(const Decl *D) {
+  if (const VarDecl *Var = dyn_cast_or_null(D))
+return Var->isConstexpr();
+
+  return false;
+}
+
 Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
   // RAII type used to track whether we're inside an initializer.
@@ -2561,9 +2568,12 @@ Decl 
*Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Parser &P;
 Declarator &D;
 Decl *ThisDecl;
+llvm::SaveAndRestore ConstantContext;
 
 InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl)
-: P(P), D(D), ThisDecl(ThisDecl) {
+: P(P), D(D), ThisDecl(ThisDecl),
+  ConstantContext(P.Actions.isConstantEvaluatedOverride,
+  isConstexprVariable(ThisDecl)) {
   if (ThisDecl && P.getLangOpts().CPlusPlus) {
 Scope *S = nullptr;
 if (D.getCXXScopeSpec().isSet()) {
diff --git a/clang/test/CXX/expr/expr.const/p6-2a.cpp 
b/clang/test/CXX/expr/expr.const/p6-2a.cpp
index a937474d53b221..8b940b2ee9fb2a 100644
--- a/clang/test/CXX/expr/expr.const/p6-2a.cpp
+++ b/clang/test/CXX/expr/expr.const/p6-2a.cpp
@@ -43,12 +43,11 @@ struct Temporary {
 constexpr Temporary t = {3}; // expected-error {{must have constant 
destruction}} expected-note {{created here}} expected-note {{in call}}
 
 namespace P1073R3 {
-consteval int f() { return 42; } // expected-note 2 {{declared here}}
+consteval int f() { return 42; } // expected-note {{declared here}}
 consteval auto g() { return f; }
 consteval int h(int (*p)() = g()) { return p(); }
 constexpr int r = h();
-constexpr auto e = g();  // expected-error {{call to consteval function 
'P1073R3::g' is not a constant expression}} \
-expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
-expected-note 2 {{pointer to a consteval 
declaration is not a constant expression}}
+constexpr auto e = g();  // expected-error {{constexpr variable 'e' must be 
initialized by a constant expression}} \
+expected-note {{pointer to a consteval declaration 
is not a constant expression}}
 static_assert(r == 42);
 } // namespace P1073R3
diff --git a/clang/test/SemaCXX/builtin_vectorelements.cpp 
b/clang/test/SemaCXX/builtin_vectorelements.cpp
index 59ff09ac72e42d..12f2cbe57bd47d 100644
--- a/clang/test/SemaCXX/builtin_vectorelements.cpp
+++ b/clang/test/SemaCXX/builtin_vectorelements.cpp
@@ -42,11 +42,11 @@ void test_builtin_vectorelements() {
 #include 
 
 consteval int consteval_elements() { // expected-error {{consteval function 
never produces a constant expression}}
-  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}}  
// expected-note {{cannot determine number of elements for sizeless vectors in 
a constant expression}} // expected-note {{cannot determine number of elements 
for sizeless vectors in a constant expression}}
+  return __builtin_vectorelements(svuint64_t); // expected-note {{cannot 
determine number of elements for sizeless vectors in a constant expression}} // 
expected-note {{cannot determine number of elements for sizeless vectors in a 
constant expression}}
 }
 
 void test_bad_constexpr() {
-  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-error {{not a constant expression}} // 
expected-note {{in call}} // expected-note {{in call}}
+  constexpr int eval = consteval_elements(); // expected-error {{initialized 
by a constant expression}} // expected-note {{in call}}
   constexpr int i32 = __builtin_vectorelements(svuint32_t); // expected-error 
{{initialized by a constant expression}} // expected-note {{cannot determine 
number of elements for sizeless vectors in a constant expression}}
   constexpr int i16p8 = __builtin_vectorelements(svuint16_t) + 16; // 
expected-error

[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-22 Thread Daniel M. Katz via cfe-commits

katzdm wrote:

> I think the change makes sense. Can you add a release note?

Appreciate the reminder!

https://github.com/llvm/llvm-project/pull/89565
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Don't wrap immediate invocations in ConstantExprs within constexpr initializers (PR #89565)

2024-04-21 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm created 
https://github.com/llvm/llvm-project/pull/89565

The following program produces a diagnostic in Clang and EDG, but compiles 
correctly in GCC and MSVC:
```cpp
#include 

consteval std::vector fn() { return {1,2,3}; }
constexpr int a = fn()[1];
```

Clang's diagnostic is as follows:
```cpp
:6:19: error: call to consteval function 'fn' is not a constant 
expression
6 | constexpr int a = fn()[1];
  |   ^
:6:19: note: pointer to subobject of heap-allocated object is not a 
constant expression
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.1/../../../../include/c++/14.0.1/bits/allocator.h:193:31:
 note: heap allocation performed here
  193 | return static_cast<_Tp*>(::operator new(__n));
  |  ^
1 error generated.
Compiler returned: 1
```

Based on my understanding of 
[`[dcl.constexpr]/6`](https://eel.is/c++draft/dcl.constexpr#6):
> In any constexpr variable declaration, the full-expression of the 
> initialization shall be a constant expression

It seems to me that GCC and MSVC are correct: the initializer `fn()[1]` does 
not evaluate to an lvalue referencing a heap-allocated value within the 
`vector` returned by `fn()`; it evaluates to an lvalue-to-rvalue conversion 
_from_ that heap-allocated value.

A dump of the AST for the variable declaration elucidates what I believe to be 
a problem:
```
`-VarDecl  col:15 a 'const int' constexpr cinit
  |-value: Int 2
  `-ExprWithCleanups  'value_type':'int'
`-ImplicitCastExpr  'value_type':'int' 
  `-CXXOperatorCallExpr  'value_type':'int' lvalue '[]'
|-ImplicitCastExpr  'reference (*)(size_type) noexcept' 

| `-DeclRefExpr  'reference (size_type) noexcept' 
lvalue CXXMethod 0xd1497a0 'operator[]' 'reference (size_type) noexcept'
|-MaterializeTemporaryExpr  'std::vector' lvalue
| `-ConstantExpr  'std::vector'
|   `-ExprWithCleanups  'std::vector'
| `-CXXBindTemporaryExpr  'std::vector' 
(CXXTemporary 0xd180de8)
|   `-CallExpr  'std::vector'
| `-ImplicitCastExpr  'std::vector (*)()' 

|   `-DeclRefExpr  'std::vector ()' lvalue 
Function 0xd12e7b8 'fn' 'std::vector ()'
`-ImplicitCastExpr  'size_type':'unsigned long' 
  `-IntegerLiteral  'int' 1
```

There is a `ConstantExpr` wrapping the `CallExpr` to `fn`, causing it to be 
evaluated independently as a constant expression rather than evaluated as a 
component of the larger LValueToRValue-ImplicitCastExpr. Because the 
initializer of any constexpr variable declaration is itself a constant 
expression (as cited above), I believe this is incorrect.

The `ConstantExpr` wrapper is created because `fn()` is an immediate function 
call within an evaluation context that Clang [classifies as 
`PotentiallyEvaluated`](https://github.com/llvm/llvm-project/blob/main/clang/lib/Sema/SemaDeclCXX.cpp#L18579-L18581)
 rather than `ConstantEvaluated`. Setting the 
`Sema::isConstantEvaluatedOverride` flag during evaluation of an initializer 
seems to address the problem.

I added a test to `clang/test/SemaCXX/cxx2a-consteval.cpp` to cover this case, 
and "fixed" the few tests that fail in response to it. [One such 
test](https://github.com/llvm/llvm-project/compare/main...katzdm:constexpr-init-fix?expand=1#diff-f10defc3f20fb095bf22b3a79bead200d494bde9d503e283067a57aff483936cL729)
 was documented by a `FIXME` that this change appears to fix.

Most of the other changes to tests consist of removing annotations expecting 
diagnostics for the issue being fixed here - from a quick spot check, nothing 
jumped out as "hey, that looks like it really should be an error", but another 
set of eyes would be helpful here.

>From a3f8a8648e2002273d47d7886b29fb02c728b5b7 Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Tue, 16 Apr 2024 17:14:50 -0400
Subject: [PATCH] Fix bug with constexpr initialization.

---
 clang/lib/Parse/ParseDecl.cpp | 12 ++-
 clang/test/CXX/expr/expr.const/p6-2a.cpp  |  7 ++--
 clang/test/SemaCXX/builtin_vectorelements.cpp |  4 +--
 clang/test/SemaCXX/cxx2a-consteval.cpp| 32 ---
 clang/unittests/Support/TimeProfilerTest.cpp  |  1 -
 5 files changed, 36 insertions(+), 20 deletions(-)

diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 583232f2d610d0..0ea6fccaa7eb34 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2554,6 +2554,13 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
   return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
 }
 
+static bool isConstexprVariable(const Decl *D) {
+  if (const VarDecl *Var = dyn_cast_or_null(D))
+return Var->isConstexpr();
+
+  return false;
+}
+
 Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
   // RAII type used to track w

[clang] Raise an error on namespace aliases with qualified names. (PR #86122)

2024-03-21 Thread Daniel M. Katz via cfe-commits

katzdm wrote:

> You can ignore the merge conflicts in the release notes; it’s better to let 
> whoever ends up merging this (probably me) take care of that when it comes to 
> the release notes (because they get updated constantly).

Ah, missed this - already fixed it. Will ignore if it happens again.

https://github.com/llvm/llvm-project/pull/86122
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] Raise an error on namespace aliases with qualified names. (PR #86122)

2024-03-21 Thread Daniel M. Katz via cfe-commits


@@ -33,6 +33,7 @@ def get_num_tests(self, path, litConfig, localConfig):
 [path, "--gtest_list_tests", "--gtest_filter=-*DISABLED_*"]
 )
 try:
+localConfig.environment['DYLD_LIBRARY_PATH'] = ''

katzdm wrote:

I did not. I should also figure out one of these days why I need it πŸ˜‚ 

https://github.com/llvm/llvm-project/pull/86122
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] Raise an error on namespace aliases with qualified names. (PR #86122)

2024-03-21 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/86122

>From 319b7d99b4010514a1680ffd99fb0586b5e7221d Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Thu, 21 Mar 2024 09:47:04 -0400
Subject: [PATCH 1/4] Raise an error on namespace aliases with qualified names.

Current behavior is to ignore the trailing qualifiers, but the grammar
for `namespace-alias-definition` requires an `identifier` without
qualification.

https://godbolt.org/z/1zvW5q4f8

https://eel.is/c++draft/namespace.alias#nt:namespace-alias-definition
---
 clang/include/clang/Basic/DiagnosticParseKinds.td | 2 ++
 clang/lib/Parse/ParseDeclCXX.cpp  | 5 +
 clang/test/SemaCXX/namespace-alias.cpp| 2 ++
 3 files changed, 9 insertions(+)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 816c3ff5f8b2aa..d45a1f0b6ad1c0 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -268,6 +268,8 @@ def err_expected_semi_after_namespace_name : Error<
   "expected ';' after namespace name">;
 def err_unexpected_namespace_attributes_alias : Error<
   "attributes cannot be specified on namespace alias">;
+def err_unexpected_qualified_namespace_alias : Error<
+  "unexpected nested name specifier in namespace alias definition">;
 def err_unexpected_nested_namespace_attribute : Error<
   "attributes cannot be specified on a nested namespace definition">;
 def err_inline_namespace_alias : Error<"namespace alias cannot be inline">;
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 77d2382ea6d907..0ef2f2fad2a9d1 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -140,6 +140,11 @@ Parser::DeclGroupPtrTy 
Parser::ParseNamespace(DeclaratorContext Context,
   SkipUntil(tok::semi);
   return nullptr;
 }
+if (!ExtraNSs.empty()) {
+  Diag(IdentLoc, diag::err_unexpected_qualified_namespace_alias);
+  SkipUntil(tok::semi);
+  return nullptr;
+}
 if (attrLoc.isValid())
   Diag(attrLoc, diag::err_unexpected_namespace_attributes_alias);
 if (InlineLoc.isValid())
diff --git a/clang/test/SemaCXX/namespace-alias.cpp 
b/clang/test/SemaCXX/namespace-alias.cpp
index 281ee9962e8b52..10d2e8beeccaa0 100644
--- a/clang/test/SemaCXX/namespace-alias.cpp
+++ b/clang/test/SemaCXX/namespace-alias.cpp
@@ -47,6 +47,8 @@ namespace I {
   namespace A1 { int i; }
   
   namespace A2 = A1;
+
+  namespace A3::extra::specifiers = A2;  // expected-error {{unexpected nested 
name specifier}}
 }
 
 int f() {

>From d28b8e1f6782f69e2c49151cae1d9898f331f0b9 Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Thu, 21 Mar 2024 11:44:03 -0400
Subject: [PATCH 2/4] Addressing feedback.

---
 clang/include/clang/Basic/DiagnosticParseKinds.td | 2 +-
 clang/lib/Parse/ParseDeclCXX.cpp  | 5 -
 clang/test/SemaCXX/namespace-alias.cpp| 2 +-
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index d45a1f0b6ad1c0..6290a08fcf4d3b 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -269,7 +269,7 @@ def err_expected_semi_after_namespace_name : Error<
 def err_unexpected_namespace_attributes_alias : Error<
   "attributes cannot be specified on namespace alias">;
 def err_unexpected_qualified_namespace_alias : Error<
-  "unexpected nested name specifier in namespace alias definition">;
+  "namespace alias must be a single identifier">;
 def err_unexpected_nested_namespace_attribute : Error<
   "attributes cannot be specified on a nested namespace definition">;
 def err_inline_namespace_alias : Error<"namespace alias cannot be inline">;
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 0ef2f2fad2a9d1..63fe678cbb29e2 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -141,7 +141,10 @@ Parser::DeclGroupPtrTy 
Parser::ParseNamespace(DeclaratorContext Context,
   return nullptr;
 }
 if (!ExtraNSs.empty()) {
-  Diag(IdentLoc, diag::err_unexpected_qualified_namespace_alias);
+  Diag(ExtraNSs.front().NamespaceLoc,
+   diag::err_unexpected_qualified_namespace_alias)
+  << SourceRange(ExtraNSs.front().NamespaceLoc,
+ ExtraNSs.back().IdentLoc);
   SkipUntil(tok::semi);
   return nullptr;
 }
diff --git a/clang/test/SemaCXX/namespace-alias.cpp 
b/clang/test/SemaCXX/namespace-alias.cpp
index 10d2e8beeccaa0..591957a657c03a 100644
--- a/clang/test/SemaCXX/namespace-alias.cpp
+++ b/clang/test/SemaCXX/namespace-alias.cpp
@@ -48,7 +48,7 @@ namespace I {
   
   namespace A2 = A1;
 
-  namespace A3::extra::specifiers = A2;  // expected-error {{unexpected nested 
name specifier}}
+  names

[clang] Raise an error on namespace aliases with qualified names. (PR #86122)

2024-03-21 Thread Daniel M. Katz via cfe-commits


@@ -33,6 +33,7 @@ def get_num_tests(self, path, litConfig, localConfig):
 [path, "--gtest_list_tests", "--gtest_filter=-*DISABLED_*"]
 )
 try:
+localConfig.environment['DYLD_LIBRARY_PATH'] = ''

katzdm wrote:

Done, thanks for noticing that.

https://github.com/llvm/llvm-project/pull/86122
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Raise an error on namespace aliases with qualified names. (PR #86122)

2024-03-21 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/86122

>From 1998809477ce9ef03516278e1f0e9084426ea7f2 Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Thu, 21 Mar 2024 09:47:04 -0400
Subject: [PATCH 1/4] Raise an error on namespace aliases with qualified names.

Current behavior is to ignore the trailing qualifiers, but the grammar
for `namespace-alias-definition` requires an `identifier` without
qualification.

https://godbolt.org/z/1zvW5q4f8

https://eel.is/c++draft/namespace.alias#nt:namespace-alias-definition
---
 clang/include/clang/Basic/DiagnosticParseKinds.td | 2 ++
 clang/lib/Parse/ParseDeclCXX.cpp  | 5 +
 clang/test/SemaCXX/namespace-alias.cpp| 2 ++
 3 files changed, 9 insertions(+)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 48de5e2ef5f4af..5626307c80c2df 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -268,6 +268,8 @@ def err_expected_semi_after_namespace_name : Error<
   "expected ';' after namespace name">;
 def err_unexpected_namespace_attributes_alias : Error<
   "attributes cannot be specified on namespace alias">;
+def err_unexpected_qualified_namespace_alias : Error<
+  "unexpected nested name specifier in namespace alias definition">;
 def err_unexpected_nested_namespace_attribute : Error<
   "attributes cannot be specified on a nested namespace definition">;
 def err_inline_namespace_alias : Error<"namespace alias cannot be inline">;
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 77d2382ea6d907..0ef2f2fad2a9d1 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -140,6 +140,11 @@ Parser::DeclGroupPtrTy 
Parser::ParseNamespace(DeclaratorContext Context,
   SkipUntil(tok::semi);
   return nullptr;
 }
+if (!ExtraNSs.empty()) {
+  Diag(IdentLoc, diag::err_unexpected_qualified_namespace_alias);
+  SkipUntil(tok::semi);
+  return nullptr;
+}
 if (attrLoc.isValid())
   Diag(attrLoc, diag::err_unexpected_namespace_attributes_alias);
 if (InlineLoc.isValid())
diff --git a/clang/test/SemaCXX/namespace-alias.cpp 
b/clang/test/SemaCXX/namespace-alias.cpp
index 281ee9962e8b52..10d2e8beeccaa0 100644
--- a/clang/test/SemaCXX/namespace-alias.cpp
+++ b/clang/test/SemaCXX/namespace-alias.cpp
@@ -47,6 +47,8 @@ namespace I {
   namespace A1 { int i; }
   
   namespace A2 = A1;
+
+  namespace A3::extra::specifiers = A2;  // expected-error {{unexpected nested 
name specifier}}
 }
 
 int f() {

>From e40b7af1981866adb21892305a0f9dfaa5bdc8eb Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Thu, 21 Mar 2024 11:44:03 -0400
Subject: [PATCH 2/4] Addressing feedback.

---
 clang/include/clang/Basic/DiagnosticParseKinds.td | 2 +-
 clang/lib/Parse/ParseDeclCXX.cpp  | 5 -
 clang/test/SemaCXX/namespace-alias.cpp| 2 +-
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 5626307c80c2df..46a44418a3153b 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -269,7 +269,7 @@ def err_expected_semi_after_namespace_name : Error<
 def err_unexpected_namespace_attributes_alias : Error<
   "attributes cannot be specified on namespace alias">;
 def err_unexpected_qualified_namespace_alias : Error<
-  "unexpected nested name specifier in namespace alias definition">;
+  "namespace alias must be a single identifier">;
 def err_unexpected_nested_namespace_attribute : Error<
   "attributes cannot be specified on a nested namespace definition">;
 def err_inline_namespace_alias : Error<"namespace alias cannot be inline">;
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 0ef2f2fad2a9d1..63fe678cbb29e2 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -141,7 +141,10 @@ Parser::DeclGroupPtrTy 
Parser::ParseNamespace(DeclaratorContext Context,
   return nullptr;
 }
 if (!ExtraNSs.empty()) {
-  Diag(IdentLoc, diag::err_unexpected_qualified_namespace_alias);
+  Diag(ExtraNSs.front().NamespaceLoc,
+   diag::err_unexpected_qualified_namespace_alias)
+  << SourceRange(ExtraNSs.front().NamespaceLoc,
+ ExtraNSs.back().IdentLoc);
   SkipUntil(tok::semi);
   return nullptr;
 }
diff --git a/clang/test/SemaCXX/namespace-alias.cpp 
b/clang/test/SemaCXX/namespace-alias.cpp
index 10d2e8beeccaa0..591957a657c03a 100644
--- a/clang/test/SemaCXX/namespace-alias.cpp
+++ b/clang/test/SemaCXX/namespace-alias.cpp
@@ -48,7 +48,7 @@ namespace I {
   
   namespace A2 = A1;
 
-  namespace A3::extra::specifiers = A2;  // expected-error {{unexpected nested 
name specifier}}
+  names

[clang] Raise an error on namespace aliases with qualified names. (PR #86122)

2024-03-21 Thread Daniel M. Katz via cfe-commits


@@ -394,6 +394,8 @@ Bug Fixes to C++ Support
   expression references to an entity declared outside of the lambda. (#GH64808)
 - Clang's __builtin_bit_cast will now produce a constant value for records 
with empty bases. See:
   (#GH82383)
+- Fix an issue where a namespace alias could be defined using a qualified name 
(all name components
+following the first `::` were ignored). (#GH86122)

katzdm wrote:

Good to know! Fixed.

https://github.com/llvm/llvm-project/pull/86122
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Raise an error on namespace aliases with qualified names. (PR #86122)

2024-03-21 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/86122

>From 319b7d99b4010514a1680ffd99fb0586b5e7221d Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Thu, 21 Mar 2024 09:47:04 -0400
Subject: [PATCH 1/3] Raise an error on namespace aliases with qualified names.

Current behavior is to ignore the trailing qualifiers, but the grammar
for `namespace-alias-definition` requires an `identifier` without
qualification.

https://godbolt.org/z/1zvW5q4f8

https://eel.is/c++draft/namespace.alias#nt:namespace-alias-definition
---
 clang/include/clang/Basic/DiagnosticParseKinds.td | 2 ++
 clang/lib/Parse/ParseDeclCXX.cpp  | 5 +
 clang/test/SemaCXX/namespace-alias.cpp| 2 ++
 3 files changed, 9 insertions(+)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 816c3ff5f8b2aa..d45a1f0b6ad1c0 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -268,6 +268,8 @@ def err_expected_semi_after_namespace_name : Error<
   "expected ';' after namespace name">;
 def err_unexpected_namespace_attributes_alias : Error<
   "attributes cannot be specified on namespace alias">;
+def err_unexpected_qualified_namespace_alias : Error<
+  "unexpected nested name specifier in namespace alias definition">;
 def err_unexpected_nested_namespace_attribute : Error<
   "attributes cannot be specified on a nested namespace definition">;
 def err_inline_namespace_alias : Error<"namespace alias cannot be inline">;
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 77d2382ea6d907..0ef2f2fad2a9d1 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -140,6 +140,11 @@ Parser::DeclGroupPtrTy 
Parser::ParseNamespace(DeclaratorContext Context,
   SkipUntil(tok::semi);
   return nullptr;
 }
+if (!ExtraNSs.empty()) {
+  Diag(IdentLoc, diag::err_unexpected_qualified_namespace_alias);
+  SkipUntil(tok::semi);
+  return nullptr;
+}
 if (attrLoc.isValid())
   Diag(attrLoc, diag::err_unexpected_namespace_attributes_alias);
 if (InlineLoc.isValid())
diff --git a/clang/test/SemaCXX/namespace-alias.cpp 
b/clang/test/SemaCXX/namespace-alias.cpp
index 281ee9962e8b52..10d2e8beeccaa0 100644
--- a/clang/test/SemaCXX/namespace-alias.cpp
+++ b/clang/test/SemaCXX/namespace-alias.cpp
@@ -47,6 +47,8 @@ namespace I {
   namespace A1 { int i; }
   
   namespace A2 = A1;
+
+  namespace A3::extra::specifiers = A2;  // expected-error {{unexpected nested 
name specifier}}
 }
 
 int f() {

>From d28b8e1f6782f69e2c49151cae1d9898f331f0b9 Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Thu, 21 Mar 2024 11:44:03 -0400
Subject: [PATCH 2/3] Addressing feedback.

---
 clang/include/clang/Basic/DiagnosticParseKinds.td | 2 +-
 clang/lib/Parse/ParseDeclCXX.cpp  | 5 -
 clang/test/SemaCXX/namespace-alias.cpp| 2 +-
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index d45a1f0b6ad1c0..6290a08fcf4d3b 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -269,7 +269,7 @@ def err_expected_semi_after_namespace_name : Error<
 def err_unexpected_namespace_attributes_alias : Error<
   "attributes cannot be specified on namespace alias">;
 def err_unexpected_qualified_namespace_alias : Error<
-  "unexpected nested name specifier in namespace alias definition">;
+  "namespace alias must be a single identifier">;
 def err_unexpected_nested_namespace_attribute : Error<
   "attributes cannot be specified on a nested namespace definition">;
 def err_inline_namespace_alias : Error<"namespace alias cannot be inline">;
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 0ef2f2fad2a9d1..63fe678cbb29e2 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -141,7 +141,10 @@ Parser::DeclGroupPtrTy 
Parser::ParseNamespace(DeclaratorContext Context,
   return nullptr;
 }
 if (!ExtraNSs.empty()) {
-  Diag(IdentLoc, diag::err_unexpected_qualified_namespace_alias);
+  Diag(ExtraNSs.front().NamespaceLoc,
+   diag::err_unexpected_qualified_namespace_alias)
+  << SourceRange(ExtraNSs.front().NamespaceLoc,
+ ExtraNSs.back().IdentLoc);
   SkipUntil(tok::semi);
   return nullptr;
 }
diff --git a/clang/test/SemaCXX/namespace-alias.cpp 
b/clang/test/SemaCXX/namespace-alias.cpp
index 10d2e8beeccaa0..591957a657c03a 100644
--- a/clang/test/SemaCXX/namespace-alias.cpp
+++ b/clang/test/SemaCXX/namespace-alias.cpp
@@ -48,7 +48,7 @@ namespace I {
   
   namespace A2 = A1;
 
-  namespace A3::extra::specifiers = A2;  // expected-error {{unexpected nested 
name specifier}}
+  names

[clang] Raise an error on namespace aliases with qualified names. (PR #86122)

2024-03-21 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm updated 
https://github.com/llvm/llvm-project/pull/86122

>From 319b7d99b4010514a1680ffd99fb0586b5e7221d Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Thu, 21 Mar 2024 09:47:04 -0400
Subject: [PATCH 1/2] Raise an error on namespace aliases with qualified names.

Current behavior is to ignore the trailing qualifiers, but the grammar
for `namespace-alias-definition` requires an `identifier` without
qualification.

https://godbolt.org/z/1zvW5q4f8

https://eel.is/c++draft/namespace.alias#nt:namespace-alias-definition
---
 clang/include/clang/Basic/DiagnosticParseKinds.td | 2 ++
 clang/lib/Parse/ParseDeclCXX.cpp  | 5 +
 clang/test/SemaCXX/namespace-alias.cpp| 2 ++
 3 files changed, 9 insertions(+)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 816c3ff5f8b2aa..d45a1f0b6ad1c0 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -268,6 +268,8 @@ def err_expected_semi_after_namespace_name : Error<
   "expected ';' after namespace name">;
 def err_unexpected_namespace_attributes_alias : Error<
   "attributes cannot be specified on namespace alias">;
+def err_unexpected_qualified_namespace_alias : Error<
+  "unexpected nested name specifier in namespace alias definition">;
 def err_unexpected_nested_namespace_attribute : Error<
   "attributes cannot be specified on a nested namespace definition">;
 def err_inline_namespace_alias : Error<"namespace alias cannot be inline">;
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 77d2382ea6d907..0ef2f2fad2a9d1 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -140,6 +140,11 @@ Parser::DeclGroupPtrTy 
Parser::ParseNamespace(DeclaratorContext Context,
   SkipUntil(tok::semi);
   return nullptr;
 }
+if (!ExtraNSs.empty()) {
+  Diag(IdentLoc, diag::err_unexpected_qualified_namespace_alias);
+  SkipUntil(tok::semi);
+  return nullptr;
+}
 if (attrLoc.isValid())
   Diag(attrLoc, diag::err_unexpected_namespace_attributes_alias);
 if (InlineLoc.isValid())
diff --git a/clang/test/SemaCXX/namespace-alias.cpp 
b/clang/test/SemaCXX/namespace-alias.cpp
index 281ee9962e8b52..10d2e8beeccaa0 100644
--- a/clang/test/SemaCXX/namespace-alias.cpp
+++ b/clang/test/SemaCXX/namespace-alias.cpp
@@ -47,6 +47,8 @@ namespace I {
   namespace A1 { int i; }
   
   namespace A2 = A1;
+
+  namespace A3::extra::specifiers = A2;  // expected-error {{unexpected nested 
name specifier}}
 }
 
 int f() {

>From d28b8e1f6782f69e2c49151cae1d9898f331f0b9 Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Thu, 21 Mar 2024 11:44:03 -0400
Subject: [PATCH 2/2] Addressing feedback.

---
 clang/include/clang/Basic/DiagnosticParseKinds.td | 2 +-
 clang/lib/Parse/ParseDeclCXX.cpp  | 5 -
 clang/test/SemaCXX/namespace-alias.cpp| 2 +-
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index d45a1f0b6ad1c0..6290a08fcf4d3b 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -269,7 +269,7 @@ def err_expected_semi_after_namespace_name : Error<
 def err_unexpected_namespace_attributes_alias : Error<
   "attributes cannot be specified on namespace alias">;
 def err_unexpected_qualified_namespace_alias : Error<
-  "unexpected nested name specifier in namespace alias definition">;
+  "namespace alias must be a single identifier">;
 def err_unexpected_nested_namespace_attribute : Error<
   "attributes cannot be specified on a nested namespace definition">;
 def err_inline_namespace_alias : Error<"namespace alias cannot be inline">;
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 0ef2f2fad2a9d1..63fe678cbb29e2 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -141,7 +141,10 @@ Parser::DeclGroupPtrTy 
Parser::ParseNamespace(DeclaratorContext Context,
   return nullptr;
 }
 if (!ExtraNSs.empty()) {
-  Diag(IdentLoc, diag::err_unexpected_qualified_namespace_alias);
+  Diag(ExtraNSs.front().NamespaceLoc,
+   diag::err_unexpected_qualified_namespace_alias)
+  << SourceRange(ExtraNSs.front().NamespaceLoc,
+ ExtraNSs.back().IdentLoc);
   SkipUntil(tok::semi);
   return nullptr;
 }
diff --git a/clang/test/SemaCXX/namespace-alias.cpp 
b/clang/test/SemaCXX/namespace-alias.cpp
index 10d2e8beeccaa0..591957a657c03a 100644
--- a/clang/test/SemaCXX/namespace-alias.cpp
+++ b/clang/test/SemaCXX/namespace-alias.cpp
@@ -48,7 +48,7 @@ namespace I {
   
   namespace A2 = A1;
 
-  namespace A3::extra::specifiers = A2;  // expected-error {{unexpected nested 
name specifier}}
+  names

[clang] Raise an error on namespace aliases with qualified names. (PR #86122)

2024-03-21 Thread Daniel M. Katz via cfe-commits

katzdm wrote:

@Sirraide Thanks for the quick review! I've applied your feedback. Here is an 
example error message with the patch applied:
```
test.cpp:4:20: error: namespace alias must be a single identifier
4 | namespace alias::extra::qualifiers = ::myns;
  |^~~
1 error generated.
```

https://github.com/llvm/llvm-project/pull/86122
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Raise an error on namespace aliases with qualified names. (PR #86122)

2024-03-21 Thread Daniel M. Katz via cfe-commits


@@ -268,6 +268,8 @@ def err_expected_semi_after_namespace_name : Error<
   "expected ';' after namespace name">;
 def err_unexpected_namespace_attributes_alias : Error<
   "attributes cannot be specified on namespace alias">;
+def err_unexpected_qualified_namespace_alias : Error<
+  "unexpected nested name specifier in namespace alias definition">;

katzdm wrote:

Sounds good - I was trying to think of the right phrasing and had found some 
references to "nested name specifiers" in other diagnostics. But I like your 
suggested phrasing πŸ‘ 

https://github.com/llvm/llvm-project/pull/86122
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Raise an error on namespace aliases with qualified names. (PR #86122)

2024-03-21 Thread Daniel M. Katz via cfe-commits

https://github.com/katzdm created 
https://github.com/llvm/llvm-project/pull/86122

Clang's current behavior is to ignore the trailing qualifiers, but the 
[grammar](https://eel.is/c++draft/namespace.alias#nt:namespace-alias-definition)
 for `namespace-alias-definition` requires an `identifier` without 
qualification.

https://godbolt.org/z/1zvW5q4f8

>From 319b7d99b4010514a1680ffd99fb0586b5e7221d Mon Sep 17 00:00:00 2001
From: Dan Katz 
Date: Thu, 21 Mar 2024 09:47:04 -0400
Subject: [PATCH] Raise an error on namespace aliases with qualified names.

Current behavior is to ignore the trailing qualifiers, but the grammar
for `namespace-alias-definition` requires an `identifier` without
qualification.

https://godbolt.org/z/1zvW5q4f8

https://eel.is/c++draft/namespace.alias#nt:namespace-alias-definition
---
 clang/include/clang/Basic/DiagnosticParseKinds.td | 2 ++
 clang/lib/Parse/ParseDeclCXX.cpp  | 5 +
 clang/test/SemaCXX/namespace-alias.cpp| 2 ++
 3 files changed, 9 insertions(+)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 816c3ff5f8b2aa..d45a1f0b6ad1c0 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -268,6 +268,8 @@ def err_expected_semi_after_namespace_name : Error<
   "expected ';' after namespace name">;
 def err_unexpected_namespace_attributes_alias : Error<
   "attributes cannot be specified on namespace alias">;
+def err_unexpected_qualified_namespace_alias : Error<
+  "unexpected nested name specifier in namespace alias definition">;
 def err_unexpected_nested_namespace_attribute : Error<
   "attributes cannot be specified on a nested namespace definition">;
 def err_inline_namespace_alias : Error<"namespace alias cannot be inline">;
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 77d2382ea6d907..0ef2f2fad2a9d1 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -140,6 +140,11 @@ Parser::DeclGroupPtrTy 
Parser::ParseNamespace(DeclaratorContext Context,
   SkipUntil(tok::semi);
   return nullptr;
 }
+if (!ExtraNSs.empty()) {
+  Diag(IdentLoc, diag::err_unexpected_qualified_namespace_alias);
+  SkipUntil(tok::semi);
+  return nullptr;
+}
 if (attrLoc.isValid())
   Diag(attrLoc, diag::err_unexpected_namespace_attributes_alias);
 if (InlineLoc.isValid())
diff --git a/clang/test/SemaCXX/namespace-alias.cpp 
b/clang/test/SemaCXX/namespace-alias.cpp
index 281ee9962e8b52..10d2e8beeccaa0 100644
--- a/clang/test/SemaCXX/namespace-alias.cpp
+++ b/clang/test/SemaCXX/namespace-alias.cpp
@@ -47,6 +47,8 @@ namespace I {
   namespace A1 { int i; }
   
   namespace A2 = A1;
+
+  namespace A3::extra::specifiers = A2;  // expected-error {{unexpected nested 
name specifier}}
 }
 
 int f() {

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits