[clang] [Clang] Fix synthesis of defaulted operator==/<=> when class has an anonymous struct member (PR #93380)

2024-05-25 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok created 
https://github.com/llvm/llvm-project/pull/93380

Fixes #92497

The existing implementation did try to drill into anonymous structs and compare 
them member by member, but it did not properly build up the member access 
expressions to include the anonymous struct members.

Note that this is different behaviour from GCC's anonymous struct extension 
where the defaulted comparison would compare `LHS.` with 
`RHS.`, which would fail if there is no overload for those 
types.

Example of the difference:

```c++
struct X {
struct {
bool b;
};
bool c;
template
friend constexpr bool operator==(T& L, T& R) {
// With GCC, T is the type of the anonymous struct
// With Clang, this operator isn't used
// (L.b and R.b are compared directly in the below operator==)
static_assert(sizeof(T) == sizeof(bool));
return L.b == R.b;
}
friend constexpr bool operator==(const X& L, const X& R) = default;
};

static_assert(X{} == X{});
```

This appears to be consistent with the Microsoft extension for anonymous structs

>From afb148f97eee38cdaa867cad4138bf7d7a6f6132 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sat, 25 May 2024 15:49:10 +0100
Subject: [PATCH] [Clang] Fix synthesis of defaulted operator==/<=> when class
 has an anonymous struct member

---
 clang/docs/ReleaseNotes.rst |  2 +
 clang/lib/Sema/SemaDeclCXX.cpp  | 63 ++--
 clang/test/SemaCXX/anonymous-struct.cpp | 79 -
 3 files changed, 137 insertions(+), 7 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d023f53754cb3..7985ab35439d2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -794,6 +794,8 @@ Bug Fixes to C++ Support
   Fixes (#GH87210), (GH89541).
 - Clang no longer tries to check if an expression is immediate-escalating in 
an unevaluated context.
   Fixes (#GH91308).
+- Fix defaulted ``operator==``/``operator<=>`` not working properly with
+  classes that have anonymous struct members (#GH92497).
 
 Bug Fixes to AST Handling
 ^
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 8ab429e2a136e..f573012ceacb9 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7948,7 +7948,13 @@ class DefaultedComparisonVisitor {
 
 case DefaultedComparisonKind::Equal:
 case DefaultedComparisonKind::ThreeWay:
+  assert(
+  AnonymousStructs.empty() &&
+  "Anonymous structs stack should be empty before visiting 
subobjects");
   getDerived().visitSubobjects(Results, RD, ParamLvalType.getQualifiers());
+  assert(AnonymousStructs.empty() &&
+ "Anonymous structs stack should become empty again after visiting 
"
+ "subobjects");
   return Results;
 
 case DefaultedComparisonKind::NotEqual:
@@ -7985,6 +7991,7 @@ class DefaultedComparisonVisitor {
 continue;
   // Recursively expand anonymous structs.
   if (Field->isAnonymousStructOrUnion()) {
+AnonymousStructContextRAII R(*this, Field);
 if (visitSubobjects(Results, Field->getType()->getAsCXXRecordDecl(),
 Quals))
   return true;
@@ -8027,6 +8034,30 @@ class DefaultedComparisonVisitor {
   FunctionDecl *FD;
   DefaultedComparisonKind DCK;
   UnresolvedSet<16> Fns;
+  std::vector AnonymousStructs;
+
+private:
+  struct AnonymousStructContextRAII {
+DefaultedComparisonVisitor 
+#ifndef NDEBUG
+FieldDecl *FD;
+#endif
+AnonymousStructContextRAII(AnonymousStructContextRAII &&) = delete;
+explicit AnonymousStructContextRAII(DefaultedComparisonVisitor ,
+FieldDecl *FD)
+: Self(Self) {
+#ifndef NDEBUG
+  this->FD = FD;
+#endif
+  Self.AnonymousStructs.push_back(FD);
+}
+~AnonymousStructContextRAII() {
+  assert(!Self.AnonymousStructs.empty() &&
+ Self.AnonymousStructs.back() == FD &&
+ "Invalid stack of anonymous structs");
+  Self.AnonymousStructs.pop_back();
+}
+  };
 };
 
 /// Information about a defaulted comparison, as determined by
@@ -8535,6 +8566,8 @@ class DefaultedComparisonSynthesizer
   }
 
   ExprPair getBase(CXXBaseSpecifier *Base) {
+assert(AnonymousStructs.empty() &&
+   "Visiting base class while inside an anonymous struct?");
 ExprPair Obj = getCompleteObject();
 if (Obj.first.isInvalid() || Obj.second.isInvalid())
   return {ExprError(), ExprError()};
@@ -8550,12 +8583,30 @@ class DefaultedComparisonSynthesizer
 if (Obj.first.isInvalid() || Obj.second.isInvalid())
   return {ExprError(), ExprError()};
 
-DeclAccessPair Found = DeclAccessPair::make(Field, Field->getAccess());
-DeclarationNameInfo NameInfo(Field->getDeclName(), Loc);
-return {S.BuildFieldReferenceExpr(Obj.first.get(), /*IsArrow=*/false, 

[clang] [clang] [SemaCXX] Implement CWG2627 Bit-fields and narrowing conversions (PR #78112)

2024-05-24 Thread Mital Ashok via cfe-commits

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


[clang] [clang] [SemaCXX] Implement CWG2627 Bit-fields and narrowing conversions (PR #78112)

2024-05-24 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/78112

>From 92f8720e3d21521b589d5291f086a2f32b87bfe0 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 14 Jan 2024 19:52:31 +
Subject: [PATCH 1/3] [clang] [SemaCXX] Implement CWG2627 Bit-fields and
 narrowing conversions

---
 clang/docs/ReleaseNotes.rst   |   5 +
 .../clang/Basic/DiagnosticSemaKinds.td|   3 +
 clang/include/clang/Sema/Overload.h   |   7 +-
 clang/lib/Sema/SemaExpr.cpp   |  10 +-
 clang/lib/Sema/SemaInit.cpp   |  20 ++-
 clang/lib/Sema/SemaOverload.cpp   | 119 +--
 .../dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp |  24 
 clang/test/CXX/drs/dr26xx.cpp | 136 ++
 clang/www/cxx_dr_status.html  |   2 +-
 9 files changed, 278 insertions(+), 48 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92563262cc673..28202fc604e29 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -157,6 +157,11 @@ Resolutions to C++ Defect Reports
 - Clang now diagnoses declarative nested-name-specifiers with 
pack-index-specifiers.
   (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers 
`_).
 
+- Casts from a bit-field to an integral type is now not considered narrowing 
if the
+  width of the bit-field means that all potential values are in the range
+  of the target type, even if the type of the bit-field is larger.
+  (`CWG2627. Bit-fields and narrowing conversions  
`_).
+
 C Language Changes
 --
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdca82934cb4d..6cdb439be30ae 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6253,6 +6253,9 @@ def ext_init_list_variable_narrowing_const_reference : 
ExtWarn<
 def ext_init_list_constant_narrowing : ExtWarn<
   "constant expression evaluates to %0 which cannot be narrowed to type %1">,
   InGroup, DefaultError, SFINAEFailure;
+def ext_bit_field_narrowing : Extension<
+  "narrowing non-constant-expression from %0 bit-field of width %2 to %1 is a 
C++23 extension">,
+  InGroup, SFINAEFailure;
 def ext_init_list_constant_narrowing_const_reference : ExtWarn<
   ext_init_list_constant_narrowing.Summary>,
   InGroup, DefaultError, SFINAEFailure;
diff --git a/clang/include/clang/Sema/Overload.h 
b/clang/include/clang/Sema/Overload.h
index 76311b00d2fc5..0d94045cc13f7 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -244,7 +244,11 @@ class Sema;
 /// Not a narrowing conversion.
 NK_Not_Narrowing,
 
-/// A narrowing conversion by virtue of the source and destination types.
+/// Not a narrowing conversion in C++23 because the source is a bit-field
+/// whose range can fit in the target type
+NK_BitField_Not_Narrowing,
+
+/// A narrowing conversion by virtue of the source and target types.
 NK_Type_Narrowing,
 
 /// A narrowing conversion, because a constant expression got narrowed.
@@ -387,6 +391,7 @@ class Sema;
 NarrowingKind
 getNarrowingKind(ASTContext , const Expr *Converted,
  APValue , QualType ,
+ unsigned ,
  bool IgnoreFloatToIntegralConversion = false) const;
 bool isPointerConversionToBool() const;
 bool isPointerConversionToVoidPointer(ASTContext& Context) const;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 50f92c496a539..4c16fcc60fc77 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -12361,8 +12361,9 @@ static bool checkThreeWayNarrowingConversion(Sema , 
QualType ToType, Expr *E,
 
   APValue PreNarrowingValue;
   QualType PreNarrowingType;
+  unsigned BitFieldWidth;
   switch (SCS.getNarrowingKind(S.Context, E, PreNarrowingValue,
-   PreNarrowingType,
+   PreNarrowingType, BitFieldWidth,
/*IgnoreFloatToIntegralConversion*/ true)) {
   case NK_Dependent_Narrowing:
 // Implicit conversion to a narrower type, but the expression is
@@ -12370,6 +12371,13 @@ static bool checkThreeWayNarrowingConversion(Sema , 
QualType ToType, Expr *E,
   case NK_Not_Narrowing:
 return false;
 
+  case NK_BitField_Not_Narrowing:
+if (!S.getLangOpts().CPlusPlus23) {
+  return S.Diag(E->getBeginLoc(), diag::ext_bit_field_narrowing)
+ << FromType << ToType << BitFieldWidth;
+}
+return false;
+
   case NK_Constant_Narrowing:
 // Implicit conversion to a narrower type, and the value is not a constant
 // expression.
diff --git a/clang/lib/Sema/SemaInit.cpp 

[clang] [clang] [SemaCXX] Implement CWG2627 Bit-fields and narrowing conversions (PR #78112)

2024-05-24 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/78112

>From 92f8720e3d21521b589d5291f086a2f32b87bfe0 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 14 Jan 2024 19:52:31 +
Subject: [PATCH 1/3] [clang] [SemaCXX] Implement CWG2627 Bit-fields and
 narrowing conversions

---
 clang/docs/ReleaseNotes.rst   |   5 +
 .../clang/Basic/DiagnosticSemaKinds.td|   3 +
 clang/include/clang/Sema/Overload.h   |   7 +-
 clang/lib/Sema/SemaExpr.cpp   |  10 +-
 clang/lib/Sema/SemaInit.cpp   |  20 ++-
 clang/lib/Sema/SemaOverload.cpp   | 119 +--
 .../dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp |  24 
 clang/test/CXX/drs/dr26xx.cpp | 136 ++
 clang/www/cxx_dr_status.html  |   2 +-
 9 files changed, 278 insertions(+), 48 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92563262cc673..28202fc604e29 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -157,6 +157,11 @@ Resolutions to C++ Defect Reports
 - Clang now diagnoses declarative nested-name-specifiers with 
pack-index-specifiers.
   (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers 
`_).
 
+- Casts from a bit-field to an integral type is now not considered narrowing 
if the
+  width of the bit-field means that all potential values are in the range
+  of the target type, even if the type of the bit-field is larger.
+  (`CWG2627. Bit-fields and narrowing conversions  
`_).
+
 C Language Changes
 --
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdca82934cb4d..6cdb439be30ae 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6253,6 +6253,9 @@ def ext_init_list_variable_narrowing_const_reference : 
ExtWarn<
 def ext_init_list_constant_narrowing : ExtWarn<
   "constant expression evaluates to %0 which cannot be narrowed to type %1">,
   InGroup, DefaultError, SFINAEFailure;
+def ext_bit_field_narrowing : Extension<
+  "narrowing non-constant-expression from %0 bit-field of width %2 to %1 is a 
C++23 extension">,
+  InGroup, SFINAEFailure;
 def ext_init_list_constant_narrowing_const_reference : ExtWarn<
   ext_init_list_constant_narrowing.Summary>,
   InGroup, DefaultError, SFINAEFailure;
diff --git a/clang/include/clang/Sema/Overload.h 
b/clang/include/clang/Sema/Overload.h
index 76311b00d2fc5..0d94045cc13f7 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -244,7 +244,11 @@ class Sema;
 /// Not a narrowing conversion.
 NK_Not_Narrowing,
 
-/// A narrowing conversion by virtue of the source and destination types.
+/// Not a narrowing conversion in C++23 because the source is a bit-field
+/// whose range can fit in the target type
+NK_BitField_Not_Narrowing,
+
+/// A narrowing conversion by virtue of the source and target types.
 NK_Type_Narrowing,
 
 /// A narrowing conversion, because a constant expression got narrowed.
@@ -387,6 +391,7 @@ class Sema;
 NarrowingKind
 getNarrowingKind(ASTContext , const Expr *Converted,
  APValue , QualType ,
+ unsigned ,
  bool IgnoreFloatToIntegralConversion = false) const;
 bool isPointerConversionToBool() const;
 bool isPointerConversionToVoidPointer(ASTContext& Context) const;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 50f92c496a539..4c16fcc60fc77 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -12361,8 +12361,9 @@ static bool checkThreeWayNarrowingConversion(Sema , 
QualType ToType, Expr *E,
 
   APValue PreNarrowingValue;
   QualType PreNarrowingType;
+  unsigned BitFieldWidth;
   switch (SCS.getNarrowingKind(S.Context, E, PreNarrowingValue,
-   PreNarrowingType,
+   PreNarrowingType, BitFieldWidth,
/*IgnoreFloatToIntegralConversion*/ true)) {
   case NK_Dependent_Narrowing:
 // Implicit conversion to a narrower type, but the expression is
@@ -12370,6 +12371,13 @@ static bool checkThreeWayNarrowingConversion(Sema , 
QualType ToType, Expr *E,
   case NK_Not_Narrowing:
 return false;
 
+  case NK_BitField_Not_Narrowing:
+if (!S.getLangOpts().CPlusPlus23) {
+  return S.Diag(E->getBeginLoc(), diag::ext_bit_field_narrowing)
+ << FromType << ToType << BitFieldWidth;
+}
+return false;
+
   case NK_Constant_Narrowing:
 // Implicit conversion to a narrower type, and the value is not a constant
 // expression.
diff --git a/clang/lib/Sema/SemaInit.cpp 

[clang] [Clang] Change how the argument of a delete expression is converted (PR #92814)

2024-05-23 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/92814

>From 43e9f8fe5cdb19c0f57a00b352592e56e470ffe7 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Mon, 20 May 2024 20:18:48 +0100
Subject: [PATCH 1/3] [Clang] Change how the argument of a delete expression is
 converted

A new warning -Wdelete-array is issued for the now-accepted delete of an array, 
which becomes a pointer to the first element after an array-to-pointer 
conversion.

The GNU extension of deleting a void pointer is still accepted, but if that 
void pointer comes from a conversion operator, a conversion to a pointer to an 
object type takes priority before conversions are rechecked to allow conversion 
to a void pointer.
This means that previously ambiguous contextual conversions where there was a 
conversion to a void pointer and an object pointer now unambiguously pick the 
conversion to an object pointer.
---
 clang/docs/ReleaseNotes.rst   |   4 +
 clang/include/clang/Basic/DiagnosticGroups.td |   1 +
 .../clang/Basic/DiagnosticSemaKinds.td|   1 +
 clang/lib/Sema/SemaExprCXX.cpp| 187 ++
 clang/test/CXX/drs/cwg5xx.cpp |   9 +-
 .../test/Parser/cxx2c-delete-with-message.cpp |   4 +-
 clang/www/cxx_dr_status.html  |   2 +-
 7 files changed, 117 insertions(+), 91 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 81e9d0423f96a..6e769f1f99ceb 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -749,6 +749,10 @@ Bug Fixes to C++ Support
 - Clang now correctly diagnoses when the current instantiation is used as an 
incomplete base class.
 - Clang no longer treats ``constexpr`` class scope function template 
specializations of non-static members
   as implicitly ``const`` in language modes after C++11.
+- Fix delete-expression operand not undergoing array-to-pointer conversion. 
Now warn ``-Wdelete-array`` when
+  trying to delete an array object.
+- Fix GNU extension that allows deleting ``void *`` making some deletes of 
class type ambiguous when there
+  is an object pointer and void pointer conversion operator. Now chooses the 
object pointer conversion.
 
 Bug Fixes to AST Handling
 ^
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 4cb4f3d999f7a..410c31a25db03 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -168,6 +168,7 @@ def UndefinedFuncTemplate : 
DiagGroup<"undefined-func-template">;
 def MissingNoEscape : DiagGroup<"missing-noescape">;
 
 def DefaultedFunctionDeleted : DiagGroup<"defaulted-function-deleted">;
+def DeleteArray : DiagGroup<"delete-array">;
 def DeleteIncomplete : DiagGroup<"delete-incomplete">;
 def DeleteNonAbstractNonVirtualDtor : 
DiagGroup<"delete-non-abstract-non-virtual-dtor">;
 def DeleteAbstractNonVirtualDtor : 
DiagGroup<"delete-abstract-non-virtual-dtor">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e3c65cba4886a..580f8e57804fa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7930,6 +7930,7 @@ def ext_default_init_const : ExtWarn<
   "is a Microsoft extension">,
   InGroup;
 def err_delete_operand : Error<"cannot delete expression of type %0">;
+def warn_delete_array : Warning<"deleting array of type %0">, 
InGroup;
 def ext_delete_void_ptr_operand : ExtWarn<
   "cannot delete expression with pointer-to-'void' type %0">,
   InGroup;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index f543e006060d6..9a1e149a4af8e 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3675,13 +3675,60 @@ void Sema::AnalyzeDeleteExprMismatch(FieldDecl *Field, 
SourceLocation DeleteLoc,
   }
 }
 
+namespace {
+class DeleteConverter : public Sema::ContextualImplicitConverter {
+public:
+  bool AllowVoidPointer = false;
+
+  DeleteConverter() : ContextualImplicitConverter(false, true) {}
+
+  bool match(QualType ConvType) override {
+return ConvType->isObjectPointerType() &&
+   (AllowVoidPointer || !ConvType->isVoidPointerType());
+  }
+
+  using SDB = Sema::SemaDiagnosticBuilder;
+
+  SDB diagnoseNoMatch(Sema , SourceLocation Loc, QualType T) override {
+return S.Diag(Loc, diag::err_delete_operand) << T;
+  }
+
+  SDB diagnoseIncomplete(Sema , SourceLocation Loc, QualType T) override {
+return S.Diag(Loc, diag::err_delete_incomplete_class_type) << T;
+  }
+
+  SDB diagnoseExplicitConv(Sema , SourceLocation Loc, QualType T,
+   QualType ConvTy) override {
+return S.Diag(Loc, diag::err_delete_explicit_conversion) << T << ConvTy;
+  }
+
+  SDB noteExplicitConv(Sema , CXXConversionDecl *Conv,
+   QualType ConvTy) override 

[clang] [clang] [SemaCXX] Implement CWG2627 Bit-fields and narrowing conversions (PR #78112)

2024-05-22 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/78112

>From 92f8720e3d21521b589d5291f086a2f32b87bfe0 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 14 Jan 2024 19:52:31 +
Subject: [PATCH 1/2] [clang] [SemaCXX] Implement CWG2627 Bit-fields and
 narrowing conversions

---
 clang/docs/ReleaseNotes.rst   |   5 +
 .../clang/Basic/DiagnosticSemaKinds.td|   3 +
 clang/include/clang/Sema/Overload.h   |   7 +-
 clang/lib/Sema/SemaExpr.cpp   |  10 +-
 clang/lib/Sema/SemaInit.cpp   |  20 ++-
 clang/lib/Sema/SemaOverload.cpp   | 119 +--
 .../dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp |  24 
 clang/test/CXX/drs/dr26xx.cpp | 136 ++
 clang/www/cxx_dr_status.html  |   2 +-
 9 files changed, 278 insertions(+), 48 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92563262cc673..28202fc604e29 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -157,6 +157,11 @@ Resolutions to C++ Defect Reports
 - Clang now diagnoses declarative nested-name-specifiers with 
pack-index-specifiers.
   (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers 
`_).
 
+- Casts from a bit-field to an integral type is now not considered narrowing 
if the
+  width of the bit-field means that all potential values are in the range
+  of the target type, even if the type of the bit-field is larger.
+  (`CWG2627. Bit-fields and narrowing conversions  
`_).
+
 C Language Changes
 --
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdca82934cb4d..6cdb439be30ae 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6253,6 +6253,9 @@ def ext_init_list_variable_narrowing_const_reference : 
ExtWarn<
 def ext_init_list_constant_narrowing : ExtWarn<
   "constant expression evaluates to %0 which cannot be narrowed to type %1">,
   InGroup, DefaultError, SFINAEFailure;
+def ext_bit_field_narrowing : Extension<
+  "narrowing non-constant-expression from %0 bit-field of width %2 to %1 is a 
C++23 extension">,
+  InGroup, SFINAEFailure;
 def ext_init_list_constant_narrowing_const_reference : ExtWarn<
   ext_init_list_constant_narrowing.Summary>,
   InGroup, DefaultError, SFINAEFailure;
diff --git a/clang/include/clang/Sema/Overload.h 
b/clang/include/clang/Sema/Overload.h
index 76311b00d2fc5..0d94045cc13f7 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -244,7 +244,11 @@ class Sema;
 /// Not a narrowing conversion.
 NK_Not_Narrowing,
 
-/// A narrowing conversion by virtue of the source and destination types.
+/// Not a narrowing conversion in C++23 because the source is a bit-field
+/// whose range can fit in the target type
+NK_BitField_Not_Narrowing,
+
+/// A narrowing conversion by virtue of the source and target types.
 NK_Type_Narrowing,
 
 /// A narrowing conversion, because a constant expression got narrowed.
@@ -387,6 +391,7 @@ class Sema;
 NarrowingKind
 getNarrowingKind(ASTContext , const Expr *Converted,
  APValue , QualType ,
+ unsigned ,
  bool IgnoreFloatToIntegralConversion = false) const;
 bool isPointerConversionToBool() const;
 bool isPointerConversionToVoidPointer(ASTContext& Context) const;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 50f92c496a539..4c16fcc60fc77 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -12361,8 +12361,9 @@ static bool checkThreeWayNarrowingConversion(Sema , 
QualType ToType, Expr *E,
 
   APValue PreNarrowingValue;
   QualType PreNarrowingType;
+  unsigned BitFieldWidth;
   switch (SCS.getNarrowingKind(S.Context, E, PreNarrowingValue,
-   PreNarrowingType,
+   PreNarrowingType, BitFieldWidth,
/*IgnoreFloatToIntegralConversion*/ true)) {
   case NK_Dependent_Narrowing:
 // Implicit conversion to a narrower type, but the expression is
@@ -12370,6 +12371,13 @@ static bool checkThreeWayNarrowingConversion(Sema , 
QualType ToType, Expr *E,
   case NK_Not_Narrowing:
 return false;
 
+  case NK_BitField_Not_Narrowing:
+if (!S.getLangOpts().CPlusPlus23) {
+  return S.Diag(E->getBeginLoc(), diag::ext_bit_field_narrowing)
+ << FromType << ToType << BitFieldWidth;
+}
+return false;
+
   case NK_Constant_Narrowing:
 // Implicit conversion to a narrower type, and the value is not a constant
 // expression.
diff --git a/clang/lib/Sema/SemaInit.cpp 

[clang] [Clang] Reuse tail-padding for more types that are not POD for the purpose of layout (PR #90462)

2024-05-22 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/90462

>From 96ff21d5126ebb4b9a538b8eef11f8ac9e2194c5 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Mon, 29 Apr 2024 12:27:04 +0100
Subject: [PATCH 1/2] [Clang] Reuse tail-padding for more types that are not
 POD for the purpose of layout

This will be done for types with over-large bitfields and 
potentially-overlapping ([[no_unique_address]]) members

Compatible with old Clang 18 semantics with -fclang-abi-compat

Fixes #50766
---
 clang/docs/ReleaseNotes.rst |   3 +
 clang/include/clang/Basic/LangOptions.h |   4 +-
 clang/include/clang/Basic/TargetCXXABI.h|  51 
 clang/lib/AST/RecordLayoutBuilder.cpp   | 134 +++-
 clang/test/CodeGenCXX/bitfield-layout.cpp   |  20 ++-
 clang/test/CodeGenCXX/no-unique-address.cpp |   9 +-
 clang/test/Layout/no-unique-address.cpp |  20 ++-
 7 files changed, 138 insertions(+), 103 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 604782ca43dd5..b5d76c95a24bd 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -63,6 +63,9 @@ ABI Changes in This Version
   MSVC uses a different mangling for these objects, compatibility is not 
affected.
   (#GH85423).
 
+- Fixed tail padding not being reused on types with oversized bit-fields and
+  potentially-overlapping members (#GH50766).
+
 AST Dumping Potentially Breaking Changes
 
 
diff --git a/clang/include/clang/Basic/LangOptions.h 
b/clang/include/clang/Basic/LangOptions.h
index e2a2aa71b880b..3fe1362a2d767 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -233,7 +233,9 @@ class LangOptionsBase {
 
 /// Attempt to be ABI-compatible with code generated by Clang 18.0.x.
 /// This causes clang to revert some fixes to the mangling of lambdas
-/// in the initializers of members of local classes.
+/// in the initializers of members of local classes and will not reuse
+/// tail padding on structs with potentially-overlapping members or
+/// oversized bit-fields under Itanium and some derived ABIs.
 Ver18,
 
 /// Conform to the underlying platform's C and C++ ABIs as closely
diff --git a/clang/include/clang/Basic/TargetCXXABI.h 
b/clang/include/clang/Basic/TargetCXXABI.h
index c113a6a048ad4..45d9dcc8f1b8a 100644
--- a/clang/include/clang/Basic/TargetCXXABI.h
+++ b/clang/include/clang/Basic/TargetCXXABI.h
@@ -255,57 +255,6 @@ class TargetCXXABI {
 llvm_unreachable("bad ABI kind");
   }
 
-  /// When is record layout allowed to allocate objects in the tail
-  /// padding of a base class?
-  ///
-  /// This decision cannot be changed without breaking platform ABI
-  /// compatibility. In ISO C++98, tail padding reuse was only permitted for
-  /// non-POD base classes, but that restriction was removed retroactively by
-  /// DR 43, and tail padding reuse is always permitted in all de facto C++
-  /// language modes. However, many platforms use a variant of the old C++98
-  /// rule for compatibility.
-  enum TailPaddingUseRules {
-/// The tail-padding of a base class is always theoretically
-/// available, even if it's POD.
-AlwaysUseTailPadding,
-
-/// Only allocate objects in the tail padding of a base class if
-/// the base class is not POD according to the rules of C++ TR1.
-UseTailPaddingUnlessPOD03,
-
-/// Only allocate objects in the tail padding of a base class if
-/// the base class is not POD according to the rules of C++11.
-UseTailPaddingUnlessPOD11
-  };
-  TailPaddingUseRules getTailPaddingUseRules() const {
-switch (getKind()) {
-// To preserve binary compatibility, the generic Itanium ABI has
-// permanently locked the definition of POD to the rules of C++ TR1,
-// and that trickles down to derived ABIs.
-case GenericItanium:
-case GenericAArch64:
-case GenericARM:
-case iOS:
-case GenericMIPS:
-case XL:
-  return UseTailPaddingUnlessPOD03;
-
-// AppleARM64 and WebAssembly use the C++11 POD rules.  They do not honor
-// the Itanium exception about classes with over-large bitfields.
-case AppleARM64:
-case Fuchsia:
-case WebAssembly:
-case WatchOS:
-  return UseTailPaddingUnlessPOD11;
-
-// MSVC always allocates fields in the tail-padding of a base class
-// subobject, even if they're POD.
-case Microsoft:
-  return AlwaysUseTailPadding;
-}
-llvm_unreachable("bad ABI kind");
-  }
-
   friend bool operator==(const TargetCXXABI , const TargetCXXABI ) {
 return left.getKind() == right.getKind();
   }
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp 
b/clang/lib/AST/RecordLayoutBuilder.cpp
index d9bf62c2bbb04..0b6376381a53b 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -2415,46 +2415,112 @@ DiagnosticBuilder 

[clang] [Clang] CWG2749: relational operators involving pointers to void (PR #93046)

2024-05-22 Thread Mital Ashok via cfe-commits

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


[clang] [Clang] CWG2749: relational operators involving pointers to void (PR #93046)

2024-05-22 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/93046

>From e1172958f43af7490b5b6e3752a9070265ad17ca Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Wed, 22 May 2024 16:01:13 +0100
Subject: [PATCH] [Clang] CWG2749: relational operators involving pointers to
 void

https://cplusplus.github.io/CWG/issues/2749.html

This DR's effects are backported to C++98.

Does not affect C where integral constant expressions cannot involve pointers.
---
 clang/docs/ReleaseNotes.rst   |  4 ++
 .../include/clang/Basic/DiagnosticASTKinds.td |  2 -
 clang/lib/AST/ExprConstant.cpp| 10 
 clang/test/AST/Interp/literals.cpp|  8 +---
 clang/test/CXX/drs/cwg27xx.cpp| 46 ++-
 clang/test/CXX/expr/expr.const/p2-0x.cpp  | 11 +++--
 clang/www/cxx_dr_status.html  |  2 +-
 7 files changed, 58 insertions(+), 25 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2899bc5ed35ad..4d9313f4c7ca5 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -237,6 +237,10 @@ Resolutions to C++ Defect Reports
 - P0522 implementation is enabled by default in all language versions, and
   provisional wording for CWG2398 is implemented.
 
+- Clang now allows comparing unequal object pointers that have been cast to 
``void *``
+  in constant expressions. These comparisons always worked in non-constant 
expressions.
+  (`CWG2749: Treatment of "pointer to void" for relational comparisons 
`_).
+
 C Language Changes
 --
 
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td 
b/clang/include/clang/Basic/DiagnosticASTKinds.td
index a024f9b2a9f8c..b7aae9395e635 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -148,8 +148,6 @@ def note_constexpr_var_init_weak : Note<
 def note_constexpr_typeid_polymorphic : Note<
   "typeid applied to expression of polymorphic type %0 is "
   "not allowed in a constant expression in C++ standards before C++20">;
-def note_constexpr_void_comparison : Note<
-  "comparison between unequal pointers to void has unspecified result">;
 def note_constexpr_temporary_here : Note<"temporary created here">;
 def note_constexpr_dynamic_alloc_here : Note<"heap allocation performed here">;
 def note_constexpr_conditional_never_const : Note<
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f1aa19e4409e1..d5a47a071e2cd 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13627,16 +13627,6 @@ EvaluateComparisonBinaryOperator(EvalInfo , const 
BinaryOperator *E,
 SubobjectDesignator  = LHSValue.getLValueDesignator();
 SubobjectDesignator  = RHSValue.getLValueDesignator();
 
-// C++11 [expr.rel]p3:
-//   Pointers to void (after pointer conversions) can be compared, with a
-//   result defined as follows: If both pointers represent the same
-//   address or are both the null pointer value, the result is true if the
-//   operator is <= or >= and false otherwise; otherwise the result is
-//   unspecified.
-// We interpret this as applying to pointers to *cv* void.
-if (LHSTy->isVoidPointerType() && LHSOffset != RHSOffset && IsRelational)
-  Info.CCEDiag(E, diag::note_constexpr_void_comparison);
-
 // C++11 [expr.rel]p2:
 // - If two pointers point to non-static data members of the same object,
 //   or to subobjects or array elements fo such members, recursively, the
diff --git a/clang/test/AST/Interp/literals.cpp 
b/clang/test/AST/Interp/literals.cpp
index c160be06dd241..ae7942aca39e6 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -191,12 +191,8 @@ namespace PointerComparison {
   constexpr bool v3 = null == pv; // ok
   constexpr bool v4 = qv == pv; // ok
 
-  /// FIXME: These two are rejected by the current interpreter, but
-  ///   accepted by GCC.
-  constexpr bool v5 = qv >= pv; // ref-error {{constant expression}} \
-// ref-note {{unequal pointers to void}}
-  constexpr bool v8 = qv > (void*) // ref-error {{constant expression}} \
-// ref-note {{unequal pointers to 
void}}
+  constexpr bool v5 = qv >= pv;
+  constexpr bool v8 = qv > (void*)
   constexpr bool v6 = qv > null; // both-error {{must be initialized by a 
constant expression}} \
  // both-note {{comparison between '' and 
'nullptr' has unspecified value}}
 
diff --git a/clang/test/CXX/drs/cwg27xx.cpp b/clang/test/CXX/drs/cwg27xx.cpp
index 53ddd566b7dbf..f0c3c6dbdf97b 100644
--- a/clang/test/CXX/drs/cwg27xx.cpp
+++ b/clang/test/CXX/drs/cwg27xx.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++98 -verify=expected %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu 

[clang] [Clang] CWG2749: relational operators involving pointers to void (PR #93046)

2024-05-22 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok created 
https://github.com/llvm/llvm-project/pull/93046

This DR's effects are backported to C++98.

Does not affect C where integral constant expressions cannot involve pointers.

>From aa5e7f71efdfcdea902ac881fd8db6b7c4f4538d Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Wed, 22 May 2024 16:01:13 +0100
Subject: [PATCH] [Clang] CWG2749: relational operators involving pointers to
 void

This DR's effects are backported to C++98.

Does not affect C where integral constant expressions cannot involve pointers.
---
 clang/docs/ReleaseNotes.rst   |  4 ++
 .../include/clang/Basic/DiagnosticASTKinds.td |  2 -
 clang/lib/AST/ExprConstant.cpp| 10 
 clang/test/AST/Interp/literals.cpp|  8 +---
 clang/test/CXX/drs/cwg27xx.cpp| 46 ++-
 clang/test/CXX/expr/expr.const/p2-0x.cpp  |  4 +-
 clang/www/cxx_dr_status.html  |  2 +-
 7 files changed, 54 insertions(+), 22 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2899bc5ed35ad..4d9313f4c7ca5 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -237,6 +237,10 @@ Resolutions to C++ Defect Reports
 - P0522 implementation is enabled by default in all language versions, and
   provisional wording for CWG2398 is implemented.
 
+- Clang now allows comparing unequal object pointers that have been cast to 
``void *``
+  in constant expressions. These comparisons always worked in non-constant 
expressions.
+  (`CWG2749: Treatment of "pointer to void" for relational comparisons 
`_).
+
 C Language Changes
 --
 
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td 
b/clang/include/clang/Basic/DiagnosticASTKinds.td
index a024f9b2a9f8c..b7aae9395e635 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -148,8 +148,6 @@ def note_constexpr_var_init_weak : Note<
 def note_constexpr_typeid_polymorphic : Note<
   "typeid applied to expression of polymorphic type %0 is "
   "not allowed in a constant expression in C++ standards before C++20">;
-def note_constexpr_void_comparison : Note<
-  "comparison between unequal pointers to void has unspecified result">;
 def note_constexpr_temporary_here : Note<"temporary created here">;
 def note_constexpr_dynamic_alloc_here : Note<"heap allocation performed here">;
 def note_constexpr_conditional_never_const : Note<
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f1aa19e4409e1..d5a47a071e2cd 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13627,16 +13627,6 @@ EvaluateComparisonBinaryOperator(EvalInfo , const 
BinaryOperator *E,
 SubobjectDesignator  = LHSValue.getLValueDesignator();
 SubobjectDesignator  = RHSValue.getLValueDesignator();
 
-// C++11 [expr.rel]p3:
-//   Pointers to void (after pointer conversions) can be compared, with a
-//   result defined as follows: If both pointers represent the same
-//   address or are both the null pointer value, the result is true if the
-//   operator is <= or >= and false otherwise; otherwise the result is
-//   unspecified.
-// We interpret this as applying to pointers to *cv* void.
-if (LHSTy->isVoidPointerType() && LHSOffset != RHSOffset && IsRelational)
-  Info.CCEDiag(E, diag::note_constexpr_void_comparison);
-
 // C++11 [expr.rel]p2:
 // - If two pointers point to non-static data members of the same object,
 //   or to subobjects or array elements fo such members, recursively, the
diff --git a/clang/test/AST/Interp/literals.cpp 
b/clang/test/AST/Interp/literals.cpp
index c160be06dd241..ae7942aca39e6 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -191,12 +191,8 @@ namespace PointerComparison {
   constexpr bool v3 = null == pv; // ok
   constexpr bool v4 = qv == pv; // ok
 
-  /// FIXME: These two are rejected by the current interpreter, but
-  ///   accepted by GCC.
-  constexpr bool v5 = qv >= pv; // ref-error {{constant expression}} \
-// ref-note {{unequal pointers to void}}
-  constexpr bool v8 = qv > (void*) // ref-error {{constant expression}} \
-// ref-note {{unequal pointers to 
void}}
+  constexpr bool v5 = qv >= pv;
+  constexpr bool v8 = qv > (void*)
   constexpr bool v6 = qv > null; // both-error {{must be initialized by a 
constant expression}} \
  // both-note {{comparison between '' and 
'nullptr' has unspecified value}}
 
diff --git a/clang/test/CXX/drs/cwg27xx.cpp b/clang/test/CXX/drs/cwg27xx.cpp
index 53ddd566b7dbf..f0c3c6dbdf97b 100644
--- a/clang/test/CXX/drs/cwg27xx.cpp
+++ b/clang/test/CXX/drs/cwg27xx.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu 

[clang] [clang] [SemaCXX] Implement CWG2627 Bit-fields and narrowing conversions (PR #78112)

2024-05-22 Thread Mital Ashok via cfe-commits

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


[clang] [clang] [SemaCXX] Implement CWG2627 Bit-fields and narrowing conversions (PR #78112)

2024-05-22 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/78112

>From 92f8720e3d21521b589d5291f086a2f32b87bfe0 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 14 Jan 2024 19:52:31 +
Subject: [PATCH] [clang] [SemaCXX] Implement CWG2627 Bit-fields and narrowing
 conversions

---
 clang/docs/ReleaseNotes.rst   |   5 +
 .../clang/Basic/DiagnosticSemaKinds.td|   3 +
 clang/include/clang/Sema/Overload.h   |   7 +-
 clang/lib/Sema/SemaExpr.cpp   |  10 +-
 clang/lib/Sema/SemaInit.cpp   |  20 ++-
 clang/lib/Sema/SemaOverload.cpp   | 119 +--
 .../dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp |  24 
 clang/test/CXX/drs/dr26xx.cpp | 136 ++
 clang/www/cxx_dr_status.html  |   2 +-
 9 files changed, 278 insertions(+), 48 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92563262cc673..28202fc604e29 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -157,6 +157,11 @@ Resolutions to C++ Defect Reports
 - Clang now diagnoses declarative nested-name-specifiers with 
pack-index-specifiers.
   (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers 
`_).
 
+- Casts from a bit-field to an integral type is now not considered narrowing 
if the
+  width of the bit-field means that all potential values are in the range
+  of the target type, even if the type of the bit-field is larger.
+  (`CWG2627. Bit-fields and narrowing conversions  
`_).
+
 C Language Changes
 --
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdca82934cb4d..6cdb439be30ae 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6253,6 +6253,9 @@ def ext_init_list_variable_narrowing_const_reference : 
ExtWarn<
 def ext_init_list_constant_narrowing : ExtWarn<
   "constant expression evaluates to %0 which cannot be narrowed to type %1">,
   InGroup, DefaultError, SFINAEFailure;
+def ext_bit_field_narrowing : Extension<
+  "narrowing non-constant-expression from %0 bit-field of width %2 to %1 is a 
C++23 extension">,
+  InGroup, SFINAEFailure;
 def ext_init_list_constant_narrowing_const_reference : ExtWarn<
   ext_init_list_constant_narrowing.Summary>,
   InGroup, DefaultError, SFINAEFailure;
diff --git a/clang/include/clang/Sema/Overload.h 
b/clang/include/clang/Sema/Overload.h
index 76311b00d2fc5..0d94045cc13f7 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -244,7 +244,11 @@ class Sema;
 /// Not a narrowing conversion.
 NK_Not_Narrowing,
 
-/// A narrowing conversion by virtue of the source and destination types.
+/// Not a narrowing conversion in C++23 because the source is a bit-field
+/// whose range can fit in the target type
+NK_BitField_Not_Narrowing,
+
+/// A narrowing conversion by virtue of the source and target types.
 NK_Type_Narrowing,
 
 /// A narrowing conversion, because a constant expression got narrowed.
@@ -387,6 +391,7 @@ class Sema;
 NarrowingKind
 getNarrowingKind(ASTContext , const Expr *Converted,
  APValue , QualType ,
+ unsigned ,
  bool IgnoreFloatToIntegralConversion = false) const;
 bool isPointerConversionToBool() const;
 bool isPointerConversionToVoidPointer(ASTContext& Context) const;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 50f92c496a539..4c16fcc60fc77 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -12361,8 +12361,9 @@ static bool checkThreeWayNarrowingConversion(Sema , 
QualType ToType, Expr *E,
 
   APValue PreNarrowingValue;
   QualType PreNarrowingType;
+  unsigned BitFieldWidth;
   switch (SCS.getNarrowingKind(S.Context, E, PreNarrowingValue,
-   PreNarrowingType,
+   PreNarrowingType, BitFieldWidth,
/*IgnoreFloatToIntegralConversion*/ true)) {
   case NK_Dependent_Narrowing:
 // Implicit conversion to a narrower type, but the expression is
@@ -12370,6 +12371,13 @@ static bool checkThreeWayNarrowingConversion(Sema , 
QualType ToType, Expr *E,
   case NK_Not_Narrowing:
 return false;
 
+  case NK_BitField_Not_Narrowing:
+if (!S.getLangOpts().CPlusPlus23) {
+  return S.Diag(E->getBeginLoc(), diag::ext_bit_field_narrowing)
+ << FromType << ToType << BitFieldWidth;
+}
+return false;
+
   case NK_Constant_Narrowing:
 // Implicit conversion to a narrower type, and the value is not a constant
 // expression.
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp

[clang] [Clang] Reuse tail-padding for more types that are not POD for the purpose of layout (PR #90462)

2024-05-22 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/90462

>From 96ff21d5126ebb4b9a538b8eef11f8ac9e2194c5 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Mon, 29 Apr 2024 12:27:04 +0100
Subject: [PATCH] [Clang] Reuse tail-padding for more types that are not POD
 for the purpose of layout

This will be done for types with over-large bitfields and 
potentially-overlapping ([[no_unique_address]]) members

Compatible with old Clang 18 semantics with -fclang-abi-compat

Fixes #50766
---
 clang/docs/ReleaseNotes.rst |   3 +
 clang/include/clang/Basic/LangOptions.h |   4 +-
 clang/include/clang/Basic/TargetCXXABI.h|  51 
 clang/lib/AST/RecordLayoutBuilder.cpp   | 134 +++-
 clang/test/CodeGenCXX/bitfield-layout.cpp   |  20 ++-
 clang/test/CodeGenCXX/no-unique-address.cpp |   9 +-
 clang/test/Layout/no-unique-address.cpp |  20 ++-
 7 files changed, 138 insertions(+), 103 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 604782ca43dd5..b5d76c95a24bd 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -63,6 +63,9 @@ ABI Changes in This Version
   MSVC uses a different mangling for these objects, compatibility is not 
affected.
   (#GH85423).
 
+- Fixed tail padding not being reused on types with oversized bit-fields and
+  potentially-overlapping members (#GH50766).
+
 AST Dumping Potentially Breaking Changes
 
 
diff --git a/clang/include/clang/Basic/LangOptions.h 
b/clang/include/clang/Basic/LangOptions.h
index e2a2aa71b880b..3fe1362a2d767 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -233,7 +233,9 @@ class LangOptionsBase {
 
 /// Attempt to be ABI-compatible with code generated by Clang 18.0.x.
 /// This causes clang to revert some fixes to the mangling of lambdas
-/// in the initializers of members of local classes.
+/// in the initializers of members of local classes and will not reuse
+/// tail padding on structs with potentially-overlapping members or
+/// oversized bit-fields under Itanium and some derived ABIs.
 Ver18,
 
 /// Conform to the underlying platform's C and C++ ABIs as closely
diff --git a/clang/include/clang/Basic/TargetCXXABI.h 
b/clang/include/clang/Basic/TargetCXXABI.h
index c113a6a048ad4..45d9dcc8f1b8a 100644
--- a/clang/include/clang/Basic/TargetCXXABI.h
+++ b/clang/include/clang/Basic/TargetCXXABI.h
@@ -255,57 +255,6 @@ class TargetCXXABI {
 llvm_unreachable("bad ABI kind");
   }
 
-  /// When is record layout allowed to allocate objects in the tail
-  /// padding of a base class?
-  ///
-  /// This decision cannot be changed without breaking platform ABI
-  /// compatibility. In ISO C++98, tail padding reuse was only permitted for
-  /// non-POD base classes, but that restriction was removed retroactively by
-  /// DR 43, and tail padding reuse is always permitted in all de facto C++
-  /// language modes. However, many platforms use a variant of the old C++98
-  /// rule for compatibility.
-  enum TailPaddingUseRules {
-/// The tail-padding of a base class is always theoretically
-/// available, even if it's POD.
-AlwaysUseTailPadding,
-
-/// Only allocate objects in the tail padding of a base class if
-/// the base class is not POD according to the rules of C++ TR1.
-UseTailPaddingUnlessPOD03,
-
-/// Only allocate objects in the tail padding of a base class if
-/// the base class is not POD according to the rules of C++11.
-UseTailPaddingUnlessPOD11
-  };
-  TailPaddingUseRules getTailPaddingUseRules() const {
-switch (getKind()) {
-// To preserve binary compatibility, the generic Itanium ABI has
-// permanently locked the definition of POD to the rules of C++ TR1,
-// and that trickles down to derived ABIs.
-case GenericItanium:
-case GenericAArch64:
-case GenericARM:
-case iOS:
-case GenericMIPS:
-case XL:
-  return UseTailPaddingUnlessPOD03;
-
-// AppleARM64 and WebAssembly use the C++11 POD rules.  They do not honor
-// the Itanium exception about classes with over-large bitfields.
-case AppleARM64:
-case Fuchsia:
-case WebAssembly:
-case WatchOS:
-  return UseTailPaddingUnlessPOD11;
-
-// MSVC always allocates fields in the tail-padding of a base class
-// subobject, even if they're POD.
-case Microsoft:
-  return AlwaysUseTailPadding;
-}
-llvm_unreachable("bad ABI kind");
-  }
-
   friend bool operator==(const TargetCXXABI , const TargetCXXABI ) {
 return left.getKind() == right.getKind();
   }
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp 
b/clang/lib/AST/RecordLayoutBuilder.cpp
index d9bf62c2bbb04..0b6376381a53b 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -2415,46 +2415,112 @@ DiagnosticBuilder 

[clang] [Clang] Qualified functions can't decay into pointers (PR #90353)

2024-05-21 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/90353

>From c6cd95926b0de2687f56a4966ebb5babd30ba33f Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sat, 27 Apr 2024 19:15:00 +0100
Subject: [PATCH] [Clang] Qualified functions can't decay into pointers

Fixes #27059

Dependent function parameters, template parameters and exception
declarations that have qualified function types now error instead of
silently decaying into an invalid pointer type.

Also fix __decay and __add_pointer for these types which previously
just ignored the qualifiers
---
 clang/include/clang/AST/Type.h|  4 +-
 clang/lib/AST/TypePrinter.cpp | 23 ++
 clang/lib/Sema/SemaDecl.cpp   |  7 +++
 clang/lib/Sema/SemaDeclCXX.cpp| 16 +--
 clang/lib/Sema/SemaTemplate.cpp   | 24 +-
 clang/lib/Sema/SemaType.cpp   | 46 +++
 .../dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp|  5 +-
 .../CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp   |  5 +-
 clang/test/SemaCXX/function-type-qual.cpp | 36 ++-
 clang/test/SemaCXX/type-traits.cpp| 12 +
 10 files changed, 135 insertions(+), 43 deletions(-)

diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 9a5c6e8d562c3..d7c1b74bb987f 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -5040,6 +5040,8 @@ class FunctionProtoType final
 return static_cast(FunctionTypeBits.RefQualifier);
   }
 
+  std::string getFunctionQualifiersAsString() const;
+
   using param_type_iterator = const QualType *;
 
   ArrayRef param_types() const {
@@ -7375,7 +7377,7 @@ inline bool QualType::isReferenceable() const {
   if (const auto *F = Self.getAs())
 return F->getMethodQuals().empty() && F->getRefQualifier() == RQ_None;
 
-  return false;
+  return Self.isFunctionType();
 }
 
 inline SplitQualType QualType::split() const {
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 87f0a8728d850..45f636390b74f 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2568,3 +2568,26 @@ raw_ostream ::operator<<(raw_ostream , QualType 
QT) {
   TypePrinter(LangOptions()).print(S.Ty, S.Quals, OS, /*PlaceHolder=*/"");
   return OS;
 }
+
+std::string FunctionProtoType::getFunctionQualifiersAsString() const {
+  std::string Quals = getMethodQuals().getAsString();
+
+  switch (getRefQualifier()) {
+  case RQ_None:
+break;
+
+  case RQ_LValue:
+if (!Quals.empty())
+  Quals += ' ';
+Quals += '&';
+break;
+
+  case RQ_RValue:
+if (!Quals.empty())
+  Quals += ' ';
+Quals += "&&";
+break;
+  }
+
+  return Quals;
+}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7f6921ea22be1..80e189fc92616 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15305,6 +15305,13 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, 
SourceLocation StartLoc,
 T = Context.getLifetimeQualifiedType(T, lifetime);
   }
 
+  if (T->isFunctionType() && !T.isReferenceable()) {
+Diag(NameLoc, diag::err_compound_qualified_function_type)
+<< 1 << true << T
+<< T->castAs()->getFunctionQualifiersAsString();
+return nullptr;
+  }
+
   ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name,
  Context.getAdjustedParameterType(T),
  TSInfo, SC, nullptr);
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 104e27139fe47..67d29474e1750 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -11267,7 +11267,8 @@ void Sema::CheckConversionDeclarator(Declarator , 
QualType ,
 D.setInvalidType();
   } else if (ConvType->isFunctionType()) {
 Diag(D.getIdentifierLoc(), diag::err_conv_function_to_function);
-ConvType = Context.getPointerType(ConvType);
+if (ConvType.isReferenceable())
+  ConvType = Context.getPointerType(ConvType);
 D.setInvalidType();
   }
 
@@ -16924,8 +16925,17 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, 
TypeSourceInfo *TInfo,
   // Arrays and functions decay.
   if (ExDeclType->isArrayType())
 ExDeclType = Context.getArrayDecayedType(ExDeclType);
-  else if (ExDeclType->isFunctionType())
-ExDeclType = Context.getPointerType(ExDeclType);
+  else if (ExDeclType->isFunctionType()) {
+if (ExDeclType.isReferenceable())
+  ExDeclType = Context.getPointerType(ExDeclType);
+else {
+  Diag(Loc, diag::err_compound_qualified_function_type)
+  << 1 << true << ExDeclType
+  << ExDeclType->castAs()
+ ->getFunctionQualifiersAsString();
+  Invalid = true;
+}
+  }
 
   // C++ 15.3p1: The exception-declaration shall not denote an incomplete type.
   // The exception-declaration shall not denote a pointer or reference 

[clang] [Clang] Qualified functions can't decay into pointers (PR #90353)

2024-05-21 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/90353

>From 73f6c4ee69399011a781a61283316efd491b3d28 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sat, 27 Apr 2024 19:15:00 +0100
Subject: [PATCH] [SemaCXX] Qualified functions can't decay into pointers

Fixes #27059

Dependent function parameters, template parameters and exception
declarations that have qualified function types now error instead of
silently decaying into an invalid pointer type.

Also fix __decay and __add_pointer for these types which previously
just ignored the qualifiers
---
 clang/include/clang/AST/Type.h|  4 +-
 clang/lib/AST/TypePrinter.cpp | 23 ++
 clang/lib/Sema/SemaDecl.cpp   |  7 +++
 clang/lib/Sema/SemaDeclCXX.cpp| 16 +--
 clang/lib/Sema/SemaTemplate.cpp   | 24 +-
 clang/lib/Sema/SemaType.cpp   | 46 +++
 .../dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp|  5 +-
 .../CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp   |  5 +-
 clang/test/SemaCXX/function-type-qual.cpp | 36 ++-
 clang/test/SemaCXX/type-traits.cpp| 12 +
 10 files changed, 135 insertions(+), 43 deletions(-)

diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 9a5c6e8d562c3..d7c1b74bb987f 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -5040,6 +5040,8 @@ class FunctionProtoType final
 return static_cast(FunctionTypeBits.RefQualifier);
   }
 
+  std::string getFunctionQualifiersAsString() const;
+
   using param_type_iterator = const QualType *;
 
   ArrayRef param_types() const {
@@ -7375,7 +7377,7 @@ inline bool QualType::isReferenceable() const {
   if (const auto *F = Self.getAs())
 return F->getMethodQuals().empty() && F->getRefQualifier() == RQ_None;
 
-  return false;
+  return Self.isFunctionType();
 }
 
 inline SplitQualType QualType::split() const {
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 87f0a8728d850..45f636390b74f 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2568,3 +2568,26 @@ raw_ostream ::operator<<(raw_ostream , QualType 
QT) {
   TypePrinter(LangOptions()).print(S.Ty, S.Quals, OS, /*PlaceHolder=*/"");
   return OS;
 }
+
+std::string FunctionProtoType::getFunctionQualifiersAsString() const {
+  std::string Quals = getMethodQuals().getAsString();
+
+  switch (getRefQualifier()) {
+  case RQ_None:
+break;
+
+  case RQ_LValue:
+if (!Quals.empty())
+  Quals += ' ';
+Quals += '&';
+break;
+
+  case RQ_RValue:
+if (!Quals.empty())
+  Quals += ' ';
+Quals += "&&";
+break;
+  }
+
+  return Quals;
+}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7f6921ea22be1..80e189fc92616 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15305,6 +15305,13 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, 
SourceLocation StartLoc,
 T = Context.getLifetimeQualifiedType(T, lifetime);
   }
 
+  if (T->isFunctionType() && !T.isReferenceable()) {
+Diag(NameLoc, diag::err_compound_qualified_function_type)
+<< 1 << true << T
+<< T->castAs()->getFunctionQualifiersAsString();
+return nullptr;
+  }
+
   ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name,
  Context.getAdjustedParameterType(T),
  TSInfo, SC, nullptr);
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 104e27139fe47..67d29474e1750 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -11267,7 +11267,8 @@ void Sema::CheckConversionDeclarator(Declarator , 
QualType ,
 D.setInvalidType();
   } else if (ConvType->isFunctionType()) {
 Diag(D.getIdentifierLoc(), diag::err_conv_function_to_function);
-ConvType = Context.getPointerType(ConvType);
+if (ConvType.isReferenceable())
+  ConvType = Context.getPointerType(ConvType);
 D.setInvalidType();
   }
 
@@ -16924,8 +16925,17 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, 
TypeSourceInfo *TInfo,
   // Arrays and functions decay.
   if (ExDeclType->isArrayType())
 ExDeclType = Context.getArrayDecayedType(ExDeclType);
-  else if (ExDeclType->isFunctionType())
-ExDeclType = Context.getPointerType(ExDeclType);
+  else if (ExDeclType->isFunctionType()) {
+if (ExDeclType.isReferenceable())
+  ExDeclType = Context.getPointerType(ExDeclType);
+else {
+  Diag(Loc, diag::err_compound_qualified_function_type)
+  << 1 << true << ExDeclType
+  << ExDeclType->castAs()
+ ->getFunctionQualifiersAsString();
+  Invalid = true;
+}
+  }
 
   // C++ 15.3p1: The exception-declaration shall not denote an incomplete type.
   // The exception-declaration shall not denote a pointer or 

[clang] [Clang] Qualified functions can't decay into pointers (PR #90353)

2024-05-21 Thread Mital Ashok via cfe-commits

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


[clang] [Clang] Implement CWG2351 `void{}` (PR #78060)

2024-05-21 Thread Mital Ashok via cfe-commits

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


[clang] [Clang] Implement CWG2351 `void{}` (PR #78060)

2024-05-21 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

@zygoloid The commit message was a bit outdated, it now takes the void type 
from `T` instead of the initializer list (this also preserves extra info like 
if it came from a typedef)

I've also changed it to `CK_ToVoid`

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


[clang] [Clang] Implement CWG2351 `void{}` (PR #78060)

2024-05-21 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/78060

>From 6ed7cad5d4993603221c3d9a777463675d69643b Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sat, 13 Jan 2024 18:03:15 +
Subject: [PATCH 1/2] [SemaCXX] Implement CWG2351 `void{}`

---
 clang/docs/ReleaseNotes.rst|  3 ++
 clang/include/clang/AST/ExprCXX.h  |  5 +--
 clang/lib/Sema/SemaExprCXX.cpp | 23 
 clang/lib/Sema/SemaInit.cpp|  1 +
 clang/test/CXX/drs/dr23xx.cpp  | 41 +-
 clang/test/SemaCXX/attr-annotate.cpp   |  4 +--
 clang/test/SemaCXX/cxx2a-explicit-bool.cpp |  4 +--
 clang/test/SemaCXX/sugared-auto.cpp|  6 
 clang/www/cxx_dr_status.html   |  2 +-
 9 files changed, 75 insertions(+), 14 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92563262cc673..28cd1a8abd4c6 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -157,6 +157,9 @@ Resolutions to C++ Defect Reports
 - Clang now diagnoses declarative nested-name-specifiers with 
pack-index-specifiers.
   (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers 
`_).
 
+- Implemented `CWG2351 `_ which allows ``void{}``
+  as a prvalue of type ``void``.
+
 C Language Changes
 --
 
diff --git a/clang/include/clang/AST/ExprCXX.h 
b/clang/include/clang/AST/ExprCXX.h
index a915745d2d732..8fa5c0c79f6a0 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -2170,8 +2170,9 @@ class LambdaExpr final : public Expr,
   const_child_range children() const;
 };
 
-/// An expression "T()" which creates a value-initialized rvalue of type
-/// T, which is a non-class type.  See (C++98 [5.2.3p2]).
+/// An expression "T()" which creates an rvalue of a non-class type T.
+/// For non-void T, the rvalue is value-initialized.
+/// See (C++98 [5.2.3p2]).
 class CXXScalarValueInitExpr : public Expr {
   friend class ASTStmtReader;
 
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 779a41620033d..269aedb59ca8f 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1660,12 +1660,23 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
 return ExprError(Diag(TyBeginLoc, diag::err_init_for_function_type)
<< Ty << FullRange);
 
-  // C++17 [expr.type.conv]p2:
-  //   If the type is cv void and the initializer is (), the expression is a
-  //   prvalue of the specified type that performs no initialization.
-  if (!Ty->isVoidType() &&
-  RequireCompleteType(TyBeginLoc, ElemTy,
-  diag::err_invalid_incomplete_type_use, FullRange))
+  // C++17 [expr.type.conv]p2, per DR2351:
+  //   If the type is cv void and the initializer is () or {}, the expression 
is
+  //   a prvalue of the specified type that performs no initialization.
+  if (Ty->isVoidType()) {
+if (Exprs.empty())
+  return new (Context) CXXScalarValueInitExpr(
+  Ty.getUnqualifiedType(), TInfo, Kind.getRange().getEnd());
+if (ListInitialization &&
+cast(Exprs[0])->getNumInits() == 0) {
+  return CXXFunctionalCastExpr::Create(
+  Context, Ty.getUnqualifiedType(), VK_PRValue, TInfo, CK_NoOp,
+  Exprs[0], /*Path=*/nullptr, CurFPFeatureOverrides(),
+  Exprs[0]->getBeginLoc(), Exprs[0]->getEndLoc());
+}
+  } else if (RequireCompleteType(TyBeginLoc, ElemTy,
+ diag::err_invalid_incomplete_type_use,
+ FullRange))
 return ExprError();
 
   //   Otherwise, the expression is a prvalue of the specified type whose
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 003a157990d30..3bb8407c893d9 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5344,6 +5344,7 @@ static void TryValueInitialization(Sema ,
   //
   //   To value-initialize an object of type T means:
   QualType T = Entity.getType();
+  assert(!T->isVoidType() && "Cannot value-init void");
 
   // -- if T is an array type, then each element is value-initialized;
   T = S.Context.getBaseElementType(T);
diff --git a/clang/test/CXX/drs/dr23xx.cpp b/clang/test/CXX/drs/dr23xx.cpp
index db5b7c3cd3c9a..cd21af0daf3d0 100644
--- a/clang/test/CXX/drs/dr23xx.cpp
+++ b/clang/test/CXX/drs/dr23xx.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++98 %s -verify=expected -fexceptions 
-fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -std=c++98 %s -verify=expected,cxx98-03 -fexceptions 
-fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -std=c++03 %s -verify=expected,cxx98-03 -fexceptions 
-fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
 // RUN: %clang_cc1 -std=c++11 %s -verify=expected,since-cxx11 -fexceptions 

[clang] [Clang] Implement CWG2351 `void{}` (PR #78060)

2024-05-21 Thread Mital Ashok via cfe-commits

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


[clang] [Clang] Implement CWG2351 `void{}` (PR #78060)

2024-05-21 Thread Mital Ashok via cfe-commits

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


[clang] [Clang] [C23] Fix typeof_unqual for qualified array types (PR #92767)

2024-05-21 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/92767

>From f87cb4c754a477515746e2ac2f8906b93ccd1fe3 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Mon, 20 May 2024 15:58:58 +0100
Subject: [PATCH 1/4] [Clang] [C23] Fix typeof_unqual for qualified array types

Properly remove qualifiers for both the element type and the array type

Fixes #92667
---
 clang/include/clang/AST/ASTContext.h |  6 -
 clang/include/clang/AST/Type.h   | 37 +--
 clang/lib/AST/ASTContext.cpp | 14 +-
 clang/lib/AST/Type.cpp   | 38 ++--
 clang/test/Sema/c2x-typeof.c | 25 ++
 5 files changed, 84 insertions(+), 36 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index e03b112194786..ff7bdb7e7e1a6 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -2611,7 +2611,11 @@ class ASTContext : public RefCountedBase {
   ///
   /// \returns if this is an array type, the completely unqualified array type
   /// that corresponds to it. Otherwise, returns T.getUnqualifiedType().
-  QualType getUnqualifiedArrayType(QualType T, Qualifiers );
+  QualType getUnqualifiedArrayType(QualType T, Qualifiers ) const;
+  QualType getUnqualifiedArrayType(QualType T) const {
+Qualifiers Quals;
+return getUnqualifiedArrayType(T, Quals);
+  }
 
   /// Determine whether the given types are equivalent after
   /// cvr-qualifiers have been removed.
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index da3834f19ca04..df7f396bae095 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1605,6 +1605,10 @@ class QualType {
   QualType stripObjCKindOfType(const ASTContext ) const;
 
   /// Remove all qualifiers including _Atomic.
+  ///
+  /// Like getUnqualifiedType(), the type may still be qualified if it is a
+  /// sugared array type.  To strip qualifiers even from within a sugared array
+  /// type, use ASTContext::getUnqualifiedArrayType.
   QualType getAtomicUnqualifiedType() const;
 
 private:
@@ -2092,8 +2096,8 @@ class alignas(TypeAlignment) Type : public 
ExtQualsTypeCommonBase {
 
 LLVM_PREFERRED_TYPE(TypeBitfields)
 unsigned : NumTypeBits;
-LLVM_PREFERRED_TYPE(bool)
-unsigned IsUnqual : 1; // If true: typeof_unqual, else: typeof
+LLVM_PREFERRED_TYPE(TypeOfKind)
+unsigned Kind : 1;
   };
 
   class UsingBitfields {
@@ -5273,19 +5277,20 @@ class MacroQualifiedType : public Type {
 /// extension) or a `typeof_unqual` expression (a C23 feature).
 class TypeOfExprType : public Type {
   Expr *TOExpr;
+  const ASTContext 
 
 protected:
   friend class ASTContext; // ASTContext creates these.
 
-  TypeOfExprType(Expr *E, TypeOfKind Kind, QualType Can = QualType());
+  TypeOfExprType(const ASTContext , Expr *E, TypeOfKind Kind,
+ QualType Can = QualType());
 
 public:
   Expr *getUnderlyingExpr() const { return TOExpr; }
 
   /// Returns the kind of 'typeof' type this is.
   TypeOfKind getKind() const {
-return TypeOfBits.IsUnqual ? TypeOfKind::Unqualified
-   : TypeOfKind::Qualified;
+return static_cast(TypeOfBits.Kind);
   }
 
   /// Remove a single level of sugar.
@@ -5306,7 +5311,8 @@ class TypeOfExprType : public Type {
 class DependentTypeOfExprType : public TypeOfExprType,
 public llvm::FoldingSetNode {
 public:
-  DependentTypeOfExprType(Expr *E, TypeOfKind Kind) : TypeOfExprType(E, Kind) 
{}
+  DependentTypeOfExprType(const ASTContext , Expr *E, TypeOfKind Kind)
+  : TypeOfExprType(Context, E, Kind) {}
 
   void Profile(llvm::FoldingSetNodeID , const ASTContext ) {
 Profile(ID, Context, getUnderlyingExpr(),
@@ -5323,32 +5329,23 @@ class TypeOfType : public Type {
   friend class ASTContext; // ASTContext creates these.
 
   QualType TOType;
+  const ASTContext 
 
-  TypeOfType(QualType T, QualType Can, TypeOfKind Kind)
-  : Type(TypeOf,
- Kind == TypeOfKind::Unqualified ? Can.getAtomicUnqualifiedType()
- : Can,
- T->getDependence()),
-TOType(T) {
-TypeOfBits.IsUnqual = Kind == TypeOfKind::Unqualified;
-  }
+  TypeOfType(const ASTContext , QualType T, QualType Can,
+ TypeOfKind Kind);
 
 public:
   QualType getUnmodifiedType() const { return TOType; }
 
   /// Remove a single level of sugar.
-  QualType desugar() const {
-QualType QT = getUnmodifiedType();
-return TypeOfBits.IsUnqual ? QT.getAtomicUnqualifiedType() : QT;
-  }
+  QualType desugar() const;
 
   /// Returns whether this type directly provides sugar.
   bool isSugared() const { return true; }
 
   /// Returns the kind of 'typeof' type this is.
   TypeOfKind getKind() const {
-return TypeOfBits.IsUnqual ? TypeOfKind::Unqualified
-   : 

[clang] [Clang] Change how the argument of a delete expression is converted (PR #92814)

2024-05-21 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/92814

>From 43e9f8fe5cdb19c0f57a00b352592e56e470ffe7 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Mon, 20 May 2024 20:18:48 +0100
Subject: [PATCH 1/3] [Clang] Change how the argument of a delete expression is
 converted

A new warning -Wdelete-array is issued for the now-accepted delete of an array, 
which becomes a pointer to the first element after an array-to-pointer 
conversion.

The GNU extension of deleting a void pointer is still accepted, but if that 
void pointer comes from a conversion operator, a conversion to a pointer to an 
object type takes priority before conversions are rechecked to allow conversion 
to a void pointer.
This means that previously ambiguous contextual conversions where there was a 
conversion to a void pointer and an object pointer now unambiguously pick the 
conversion to an object pointer.
---
 clang/docs/ReleaseNotes.rst   |   4 +
 clang/include/clang/Basic/DiagnosticGroups.td |   1 +
 .../clang/Basic/DiagnosticSemaKinds.td|   1 +
 clang/lib/Sema/SemaExprCXX.cpp| 187 ++
 clang/test/CXX/drs/cwg5xx.cpp |   9 +-
 .../test/Parser/cxx2c-delete-with-message.cpp |   4 +-
 clang/www/cxx_dr_status.html  |   2 +-
 7 files changed, 117 insertions(+), 91 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 81e9d0423f96a..6e769f1f99ceb 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -749,6 +749,10 @@ Bug Fixes to C++ Support
 - Clang now correctly diagnoses when the current instantiation is used as an 
incomplete base class.
 - Clang no longer treats ``constexpr`` class scope function template 
specializations of non-static members
   as implicitly ``const`` in language modes after C++11.
+- Fix delete-expression operand not undergoing array-to-pointer conversion. 
Now warn ``-Wdelete-array`` when
+  trying to delete an array object.
+- Fix GNU extension that allows deleting ``void *`` making some deletes of 
class type ambiguous when there
+  is an object pointer and void pointer conversion operator. Now chooses the 
object pointer conversion.
 
 Bug Fixes to AST Handling
 ^
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 4cb4f3d999f7a..410c31a25db03 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -168,6 +168,7 @@ def UndefinedFuncTemplate : 
DiagGroup<"undefined-func-template">;
 def MissingNoEscape : DiagGroup<"missing-noescape">;
 
 def DefaultedFunctionDeleted : DiagGroup<"defaulted-function-deleted">;
+def DeleteArray : DiagGroup<"delete-array">;
 def DeleteIncomplete : DiagGroup<"delete-incomplete">;
 def DeleteNonAbstractNonVirtualDtor : 
DiagGroup<"delete-non-abstract-non-virtual-dtor">;
 def DeleteAbstractNonVirtualDtor : 
DiagGroup<"delete-abstract-non-virtual-dtor">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e3c65cba4886a..580f8e57804fa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7930,6 +7930,7 @@ def ext_default_init_const : ExtWarn<
   "is a Microsoft extension">,
   InGroup;
 def err_delete_operand : Error<"cannot delete expression of type %0">;
+def warn_delete_array : Warning<"deleting array of type %0">, 
InGroup;
 def ext_delete_void_ptr_operand : ExtWarn<
   "cannot delete expression with pointer-to-'void' type %0">,
   InGroup;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index f543e006060d6..9a1e149a4af8e 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3675,13 +3675,60 @@ void Sema::AnalyzeDeleteExprMismatch(FieldDecl *Field, 
SourceLocation DeleteLoc,
   }
 }
 
+namespace {
+class DeleteConverter : public Sema::ContextualImplicitConverter {
+public:
+  bool AllowVoidPointer = false;
+
+  DeleteConverter() : ContextualImplicitConverter(false, true) {}
+
+  bool match(QualType ConvType) override {
+return ConvType->isObjectPointerType() &&
+   (AllowVoidPointer || !ConvType->isVoidPointerType());
+  }
+
+  using SDB = Sema::SemaDiagnosticBuilder;
+
+  SDB diagnoseNoMatch(Sema , SourceLocation Loc, QualType T) override {
+return S.Diag(Loc, diag::err_delete_operand) << T;
+  }
+
+  SDB diagnoseIncomplete(Sema , SourceLocation Loc, QualType T) override {
+return S.Diag(Loc, diag::err_delete_incomplete_class_type) << T;
+  }
+
+  SDB diagnoseExplicitConv(Sema , SourceLocation Loc, QualType T,
+   QualType ConvTy) override {
+return S.Diag(Loc, diag::err_delete_explicit_conversion) << T << ConvTy;
+  }
+
+  SDB noteExplicitConv(Sema , CXXConversionDecl *Conv,
+   QualType ConvTy) override 

[clang] [Clang] Change how the argument of a delete expression is converted (PR #92814)

2024-05-21 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/92814

>From 43e9f8fe5cdb19c0f57a00b352592e56e470ffe7 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Mon, 20 May 2024 20:18:48 +0100
Subject: [PATCH 1/2] [Clang] Change how the argument of a delete expression is
 converted

A new warning -Wdelete-array is issued for the now-accepted delete of an array, 
which becomes a pointer to the first element after an array-to-pointer 
conversion.

The GNU extension of deleting a void pointer is still accepted, but if that 
void pointer comes from a conversion operator, a conversion to a pointer to an 
object type takes priority before conversions are rechecked to allow conversion 
to a void pointer.
This means that previously ambiguous contextual conversions where there was a 
conversion to a void pointer and an object pointer now unambiguously pick the 
conversion to an object pointer.
---
 clang/docs/ReleaseNotes.rst   |   4 +
 clang/include/clang/Basic/DiagnosticGroups.td |   1 +
 .../clang/Basic/DiagnosticSemaKinds.td|   1 +
 clang/lib/Sema/SemaExprCXX.cpp| 187 ++
 clang/test/CXX/drs/cwg5xx.cpp |   9 +-
 .../test/Parser/cxx2c-delete-with-message.cpp |   4 +-
 clang/www/cxx_dr_status.html  |   2 +-
 7 files changed, 117 insertions(+), 91 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 81e9d0423f96a..6e769f1f99ceb 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -749,6 +749,10 @@ Bug Fixes to C++ Support
 - Clang now correctly diagnoses when the current instantiation is used as an 
incomplete base class.
 - Clang no longer treats ``constexpr`` class scope function template 
specializations of non-static members
   as implicitly ``const`` in language modes after C++11.
+- Fix delete-expression operand not undergoing array-to-pointer conversion. 
Now warn ``-Wdelete-array`` when
+  trying to delete an array object.
+- Fix GNU extension that allows deleting ``void *`` making some deletes of 
class type ambiguous when there
+  is an object pointer and void pointer conversion operator. Now chooses the 
object pointer conversion.
 
 Bug Fixes to AST Handling
 ^
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 4cb4f3d999f7a..410c31a25db03 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -168,6 +168,7 @@ def UndefinedFuncTemplate : 
DiagGroup<"undefined-func-template">;
 def MissingNoEscape : DiagGroup<"missing-noescape">;
 
 def DefaultedFunctionDeleted : DiagGroup<"defaulted-function-deleted">;
+def DeleteArray : DiagGroup<"delete-array">;
 def DeleteIncomplete : DiagGroup<"delete-incomplete">;
 def DeleteNonAbstractNonVirtualDtor : 
DiagGroup<"delete-non-abstract-non-virtual-dtor">;
 def DeleteAbstractNonVirtualDtor : 
DiagGroup<"delete-abstract-non-virtual-dtor">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e3c65cba4886a..580f8e57804fa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7930,6 +7930,7 @@ def ext_default_init_const : ExtWarn<
   "is a Microsoft extension">,
   InGroup;
 def err_delete_operand : Error<"cannot delete expression of type %0">;
+def warn_delete_array : Warning<"deleting array of type %0">, 
InGroup;
 def ext_delete_void_ptr_operand : ExtWarn<
   "cannot delete expression with pointer-to-'void' type %0">,
   InGroup;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index f543e006060d6..9a1e149a4af8e 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3675,13 +3675,60 @@ void Sema::AnalyzeDeleteExprMismatch(FieldDecl *Field, 
SourceLocation DeleteLoc,
   }
 }
 
+namespace {
+class DeleteConverter : public Sema::ContextualImplicitConverter {
+public:
+  bool AllowVoidPointer = false;
+
+  DeleteConverter() : ContextualImplicitConverter(false, true) {}
+
+  bool match(QualType ConvType) override {
+return ConvType->isObjectPointerType() &&
+   (AllowVoidPointer || !ConvType->isVoidPointerType());
+  }
+
+  using SDB = Sema::SemaDiagnosticBuilder;
+
+  SDB diagnoseNoMatch(Sema , SourceLocation Loc, QualType T) override {
+return S.Diag(Loc, diag::err_delete_operand) << T;
+  }
+
+  SDB diagnoseIncomplete(Sema , SourceLocation Loc, QualType T) override {
+return S.Diag(Loc, diag::err_delete_incomplete_class_type) << T;
+  }
+
+  SDB diagnoseExplicitConv(Sema , SourceLocation Loc, QualType T,
+   QualType ConvTy) override {
+return S.Diag(Loc, diag::err_delete_explicit_conversion) << T << ConvTy;
+  }
+
+  SDB noteExplicitConv(Sema , CXXConversionDecl *Conv,
+   QualType ConvTy) override 

[clang] [Clang] Change how the argument of a delete expression is converted (PR #92814)

2024-05-21 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/92814

>From 43e9f8fe5cdb19c0f57a00b352592e56e470ffe7 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Mon, 20 May 2024 20:18:48 +0100
Subject: [PATCH 1/2] [Clang] Change how the argument of a delete expression is
 converted

A new warning -Wdelete-array is issued for the now-accepted delete of an array, 
which becomes a pointer to the first element after an array-to-pointer 
conversion.

The GNU extension of deleting a void pointer is still accepted, but if that 
void pointer comes from a conversion operator, a conversion to a pointer to an 
object type takes priority before conversions are rechecked to allow conversion 
to a void pointer.
This means that previously ambiguous contextual conversions where there was a 
conversion to a void pointer and an object pointer now unambiguously pick the 
conversion to an object pointer.
---
 clang/docs/ReleaseNotes.rst   |   4 +
 clang/include/clang/Basic/DiagnosticGroups.td |   1 +
 .../clang/Basic/DiagnosticSemaKinds.td|   1 +
 clang/lib/Sema/SemaExprCXX.cpp| 187 ++
 clang/test/CXX/drs/cwg5xx.cpp |   9 +-
 .../test/Parser/cxx2c-delete-with-message.cpp |   4 +-
 clang/www/cxx_dr_status.html  |   2 +-
 7 files changed, 117 insertions(+), 91 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 81e9d0423f96a..6e769f1f99ceb 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -749,6 +749,10 @@ Bug Fixes to C++ Support
 - Clang now correctly diagnoses when the current instantiation is used as an 
incomplete base class.
 - Clang no longer treats ``constexpr`` class scope function template 
specializations of non-static members
   as implicitly ``const`` in language modes after C++11.
+- Fix delete-expression operand not undergoing array-to-pointer conversion. 
Now warn ``-Wdelete-array`` when
+  trying to delete an array object.
+- Fix GNU extension that allows deleting ``void *`` making some deletes of 
class type ambiguous when there
+  is an object pointer and void pointer conversion operator. Now chooses the 
object pointer conversion.
 
 Bug Fixes to AST Handling
 ^
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 4cb4f3d999f7a..410c31a25db03 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -168,6 +168,7 @@ def UndefinedFuncTemplate : 
DiagGroup<"undefined-func-template">;
 def MissingNoEscape : DiagGroup<"missing-noescape">;
 
 def DefaultedFunctionDeleted : DiagGroup<"defaulted-function-deleted">;
+def DeleteArray : DiagGroup<"delete-array">;
 def DeleteIncomplete : DiagGroup<"delete-incomplete">;
 def DeleteNonAbstractNonVirtualDtor : 
DiagGroup<"delete-non-abstract-non-virtual-dtor">;
 def DeleteAbstractNonVirtualDtor : 
DiagGroup<"delete-abstract-non-virtual-dtor">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e3c65cba4886a..580f8e57804fa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7930,6 +7930,7 @@ def ext_default_init_const : ExtWarn<
   "is a Microsoft extension">,
   InGroup;
 def err_delete_operand : Error<"cannot delete expression of type %0">;
+def warn_delete_array : Warning<"deleting array of type %0">, 
InGroup;
 def ext_delete_void_ptr_operand : ExtWarn<
   "cannot delete expression with pointer-to-'void' type %0">,
   InGroup;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index f543e006060d6..9a1e149a4af8e 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3675,13 +3675,60 @@ void Sema::AnalyzeDeleteExprMismatch(FieldDecl *Field, 
SourceLocation DeleteLoc,
   }
 }
 
+namespace {
+class DeleteConverter : public Sema::ContextualImplicitConverter {
+public:
+  bool AllowVoidPointer = false;
+
+  DeleteConverter() : ContextualImplicitConverter(false, true) {}
+
+  bool match(QualType ConvType) override {
+return ConvType->isObjectPointerType() &&
+   (AllowVoidPointer || !ConvType->isVoidPointerType());
+  }
+
+  using SDB = Sema::SemaDiagnosticBuilder;
+
+  SDB diagnoseNoMatch(Sema , SourceLocation Loc, QualType T) override {
+return S.Diag(Loc, diag::err_delete_operand) << T;
+  }
+
+  SDB diagnoseIncomplete(Sema , SourceLocation Loc, QualType T) override {
+return S.Diag(Loc, diag::err_delete_incomplete_class_type) << T;
+  }
+
+  SDB diagnoseExplicitConv(Sema , SourceLocation Loc, QualType T,
+   QualType ConvTy) override {
+return S.Diag(Loc, diag::err_delete_explicit_conversion) << T << ConvTy;
+  }
+
+  SDB noteExplicitConv(Sema , CXXConversionDecl *Conv,
+   QualType ConvTy) override 

[clang] [Clang] Change how the argument of a delete expression is converted (PR #92814)

2024-05-21 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

I've also found and fixed a related bug where types were compared with `==` not 
`hasSameType`, leading to two conversion operators appearing to be different 
when they are the same and Clang not compiling valid code: 
https://godbolt.org/z/nY7svGKn8

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


[clang] [Clang] Change how the argument of a delete expression is converted (PR #92814)

2024-05-21 Thread Mital Ashok via cfe-commits


@@ -1245,12 +1245,7 @@ namespace cwg599 { // cwg599: partial
 // expected-error@-1 {{cannot delete expression with pointer-to-'void' 
type 'void *'}}
 delete t;
 // expected-error@-1 {{cannot delete expression of type 'T'}}
-// FIXME: This is valid, but is rejected due to a non-conforming GNU
-// extension allowing deletion of pointers to void.
 delete u;
-// expected-error@-1 {{ambiguous conversion of delete expression of type 
'U' to a pointer}}

MitalAshok wrote:

@Endilll There is a set of appropriate types (for `delete`, it's all 
pointer-to-object types), and there must be exactly one `T` in that set where 
there is a conversion operator to cv-`T` or reference to cv-`T`. So for `delete 
u;`, the search finds `T = int*`, so `u` is contextually implicitly converted 
to `int*`. See also:  


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


[clang] [Clang] Change how the argument of a delete expression is converted (PR #92814)

2024-05-21 Thread Mital Ashok via cfe-commits


@@ -1230,11 +1230,11 @@ namespace cwg598 { // cwg598: yes
   int  = h(N::i);
 }
 
-namespace cwg599 { // cwg599: partial
+namespace cwg599 { // cwg599: 19
   typedef int Fn();
   struct S { operator void*(); };
   struct T { operator Fn*(); };
-  struct U { operator int*(); operator void*(); }; // #cwg599-U
+  struct U { operator int*(); operator void*(); };
   struct V { operator int*(); operator Fn*(); };
   void f(void *p, void (*q)(), S s, T t, U u, V v) {

MitalAshok wrote:

I've added that in another file along with other contextual implicit 
conversions with references

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


[clang] [llvm] [Clang] Fix definition of layout-compatible to ignore empty classes (PR #92103)

2024-05-21 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/92103

>From 5908130604728b9aa9b70eeb2523d368df08e68d Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Tue, 14 May 2024 08:28:19 +0100
Subject: [PATCH 1/3] [Clang] Fix definition of layout-compatible to ignore
 empty classes

Also changes the behaviour of __builtin_is_layout_compatible

None of the historic nor the current definition of layout-compatible classes 
mention anything about base classes (other than implicitly through being 
standard-layout) and are defined in terms of members, not direct members.
---
 clang/include/clang/AST/DeclCXX.h  |  7 
 clang/lib/AST/DeclCXX.cpp  | 36 +
 clang/lib/Sema/SemaChecking.cpp| 63 +-
 clang/test/SemaCXX/type-traits.cpp | 11 ++
 llvm/include/llvm/ADT/STLExtras.h  |  6 +++
 5 files changed, 79 insertions(+), 44 deletions(-)

diff --git a/clang/include/clang/AST/DeclCXX.h 
b/clang/include/clang/AST/DeclCXX.h
index fb52ac804849d..60a5005c51a5e 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1229,6 +1229,13 @@ class CXXRecordDecl : public RecordDecl {
   /// C++11 [class]p7, specifically using the C++11 rules without any DRs.
   bool isCXX11StandardLayout() const { return data().IsCXX11StandardLayout; }
 
+  /// If this is a standard-layout class or union, any and all data members 
will
+  /// be declared in the same type.
+  ///
+  /// This retrieves the type if this class has any data members,
+  /// or the current class if there is no class with fields.
+  const CXXRecordDecl *getStandardLayoutBaseWithFields() const;
+
   /// Determine whether this class, or any of its class subobjects,
   /// contains a mutable field.
   bool hasMutableFields() const { return data().HasMutableFields; }
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 75c441293d62e..ab032a4595d46 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -561,6 +561,42 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl 
*Subobj) {
 data().StructuralIfLiteral = false;
 }
 
+const CXXRecordDecl *CXXRecordDecl::getStandardLayoutBaseWithFields() const {
+#ifndef NDEBUG
+  {
+assert(
+isStandardLayout() &&
+"getStandardLayoutBaseWithFields called on a non-standard-layout 
type");
+unsigned NumberOfBasesWithFields = 0;
+if (!field_empty())
+  ++NumberOfBasesWithFields;
+std::set UniqueBases;
+forallBases([&](const CXXRecordDecl *Base) -> bool {
+  if (!Base->field_empty())
+++NumberOfBasesWithFields;
+  assert(
+  UniqueBases.insert(Base->getCanonicalDecl()).second &&
+  "Standard layout struct has multiple base classes of the same type");
+  return true;
+});
+assert(NumberOfBasesWithFields <= 1 &&
+   "Standard layout struct has fields declared in more than one 
class");
+  }
+#endif
+  if (!field_empty())
+return this;
+  const CXXRecordDecl *Result = this;
+  forallBases([&](const CXXRecordDecl *Base) -> bool {
+if (!Base->field_empty()) {
+  // This is the base where the fields are declared; return early
+  Result = Base;
+  return false;
+}
+return true;
+  });
+  return Result;
+}
+
 bool CXXRecordDecl::hasConstexprDestructor() const {
   auto *Dtor = getDestructor();
   return Dtor ? Dtor->isConstexpr() : defaultedDestructorIsConstexpr();
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ecd1821651140..acd142c1932ad 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -19084,7 +19084,8 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const 
Expr *RHSExpr,
 static bool isLayoutCompatible(ASTContext , QualType T1, QualType T2);
 
 /// Check if two enumeration types are layout-compatible.
-static bool isLayoutCompatible(ASTContext , EnumDecl *ED1, EnumDecl *ED2) {
+static bool isLayoutCompatible(ASTContext , const EnumDecl *ED1,
+   const EnumDecl *ED2) {
   // C++11 [dcl.enum] p8:
   // Two enumeration types are layout-compatible if they have the same
   // underlying type.
@@ -19095,8 +19096,8 @@ static bool isLayoutCompatible(ASTContext , EnumDecl 
*ED1, EnumDecl *ED2) {
 /// Check if two fields are layout-compatible.
 /// Can be used on union members, which are exempt from alignment requirement
 /// of common initial sequence.
-static bool isLayoutCompatible(ASTContext , FieldDecl *Field1,
-   FieldDecl *Field2,
+static bool isLayoutCompatible(ASTContext , const FieldDecl *Field1,
+   const FieldDecl *Field2,
bool AreUnionMembers = false) {
   [[maybe_unused]] const Type *Field1Parent =
   Field1->getParent()->getTypeForDecl();
@@ -19139,52 +19140,26 @@ static bool isLayoutCompatible(ASTContext , 
FieldDecl *Field1,
 
 /// Check if two standard-layout 

[clang] [llvm] [Clang] Fix definition of layout-compatible to ignore empty classes (PR #92103)

2024-05-21 Thread Mital Ashok via cfe-commits


@@ -561,6 +561,42 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl 
*Subobj) {
 data().StructuralIfLiteral = false;
 }
 
+const CXXRecordDecl *CXXRecordDecl::getStandardLayoutBaseWithFields() const {
+#ifndef NDEBUG
+  {
+assert(
+isStandardLayout() &&
+"getStandardLayoutBaseWithFields called on a non-standard-layout 
type");
+unsigned NumberOfBasesWithFields = 0;
+if (!field_empty())
+  ++NumberOfBasesWithFields;
+std::set UniqueBases;

MitalAshok wrote:

@Endilll `llvm::SmallPtrSet` seemed more appropriate here

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


[clang] [llvm] [Clang] Fix definition of layout-compatible to ignore empty classes (PR #92103)

2024-05-21 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

@dwblaikie This patch will bring Clang in line with GCC and MSVC: 
https://godbolt.org/z/nj715zbsW

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


[clang] [Clang] Change how the argument of a delete expression is converted (PR #92814)

2024-05-20 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

The array-to-pointer conversion *is* necessary, even if it's impractical to use:

https://eel.is/c++draft/expr.delete#1.sentence-5

> Otherwise, it shall be a prvalue of pointer to object type.

https://eel.is/c++draft/basic.lval#6

> Whenever a glvalue appears as an operand of an operator that requires a 
> prvalue for that operand, the lvalue-to-rvalue 
> ([[conv.lval]](https://eel.is/c++draft/conv.lval)), array-to-pointer 
> ([[conv.array]](https://eel.is/c++draft/conv.array)), or function-to-pointer 
> ([[conv.func]](https://eel.is/c++draft/conv.func)) standard conversions are 
> applied to convert the expression to a prvalue.

Deleting an array object will almost always be erroneous, which is why I've 
added the warning.

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


[clang] [Clang] Change how the argument of a delete expression is converted (PR #92814)

2024-05-20 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok created 
https://github.com/llvm/llvm-project/pull/92814

A new warning -Wdelete-array is issued for the now-accepted delete of an array, 
which becomes a pointer to the first element after an array-to-pointer 
conversion.

The GNU extension of deleting a void pointer is still accepted, but if that 
void pointer comes from a conversion operator, a conversion to a pointer to an 
object type takes priority before conversions are rechecked to allow conversion 
to a void pointer. This means that previously ambiguous contextual conversions 
where there was a conversion to a void pointer and an object pointer now 
unambiguously pick the conversion to an object pointer.

>From 43e9f8fe5cdb19c0f57a00b352592e56e470ffe7 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Mon, 20 May 2024 20:18:48 +0100
Subject: [PATCH] [Clang] Change how the argument of a delete expression is
 converted

A new warning -Wdelete-array is issued for the now-accepted delete of an array, 
which becomes a pointer to the first element after an array-to-pointer 
conversion.

The GNU extension of deleting a void pointer is still accepted, but if that 
void pointer comes from a conversion operator, a conversion to a pointer to an 
object type takes priority before conversions are rechecked to allow conversion 
to a void pointer.
This means that previously ambiguous contextual conversions where there was a 
conversion to a void pointer and an object pointer now unambiguously pick the 
conversion to an object pointer.
---
 clang/docs/ReleaseNotes.rst   |   4 +
 clang/include/clang/Basic/DiagnosticGroups.td |   1 +
 .../clang/Basic/DiagnosticSemaKinds.td|   1 +
 clang/lib/Sema/SemaExprCXX.cpp| 187 ++
 clang/test/CXX/drs/cwg5xx.cpp |   9 +-
 .../test/Parser/cxx2c-delete-with-message.cpp |   4 +-
 clang/www/cxx_dr_status.html  |   2 +-
 7 files changed, 117 insertions(+), 91 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 81e9d0423f96a..6e769f1f99ceb 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -749,6 +749,10 @@ Bug Fixes to C++ Support
 - Clang now correctly diagnoses when the current instantiation is used as an 
incomplete base class.
 - Clang no longer treats ``constexpr`` class scope function template 
specializations of non-static members
   as implicitly ``const`` in language modes after C++11.
+- Fix delete-expression operand not undergoing array-to-pointer conversion. 
Now warn ``-Wdelete-array`` when
+  trying to delete an array object.
+- Fix GNU extension that allows deleting ``void *`` making some deletes of 
class type ambiguous when there
+  is an object pointer and void pointer conversion operator. Now chooses the 
object pointer conversion.
 
 Bug Fixes to AST Handling
 ^
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 4cb4f3d999f7a..410c31a25db03 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -168,6 +168,7 @@ def UndefinedFuncTemplate : 
DiagGroup<"undefined-func-template">;
 def MissingNoEscape : DiagGroup<"missing-noescape">;
 
 def DefaultedFunctionDeleted : DiagGroup<"defaulted-function-deleted">;
+def DeleteArray : DiagGroup<"delete-array">;
 def DeleteIncomplete : DiagGroup<"delete-incomplete">;
 def DeleteNonAbstractNonVirtualDtor : 
DiagGroup<"delete-non-abstract-non-virtual-dtor">;
 def DeleteAbstractNonVirtualDtor : 
DiagGroup<"delete-abstract-non-virtual-dtor">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e3c65cba4886a..580f8e57804fa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7930,6 +7930,7 @@ def ext_default_init_const : ExtWarn<
   "is a Microsoft extension">,
   InGroup;
 def err_delete_operand : Error<"cannot delete expression of type %0">;
+def warn_delete_array : Warning<"deleting array of type %0">, 
InGroup;
 def ext_delete_void_ptr_operand : ExtWarn<
   "cannot delete expression with pointer-to-'void' type %0">,
   InGroup;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index f543e006060d6..9a1e149a4af8e 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3675,13 +3675,60 @@ void Sema::AnalyzeDeleteExprMismatch(FieldDecl *Field, 
SourceLocation DeleteLoc,
   }
 }
 
+namespace {
+class DeleteConverter : public Sema::ContextualImplicitConverter {
+public:
+  bool AllowVoidPointer = false;
+
+  DeleteConverter() : ContextualImplicitConverter(false, true) {}
+
+  bool match(QualType ConvType) override {
+return ConvType->isObjectPointerType() &&
+   (AllowVoidPointer || !ConvType->isVoidPointerType());
+  }
+
+  using SDB = 

[clang] [Clang] [C23] Fix typeof_unqual for qualified array types (PR #92767)

2024-05-20 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/92767

>From f87cb4c754a477515746e2ac2f8906b93ccd1fe3 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Mon, 20 May 2024 15:58:58 +0100
Subject: [PATCH 1/3] [Clang] [C23] Fix typeof_unqual for qualified array types

Properly remove qualifiers for both the element type and the array type

Fixes #92667
---
 clang/include/clang/AST/ASTContext.h |  6 -
 clang/include/clang/AST/Type.h   | 37 +--
 clang/lib/AST/ASTContext.cpp | 14 +-
 clang/lib/AST/Type.cpp   | 38 ++--
 clang/test/Sema/c2x-typeof.c | 25 ++
 5 files changed, 84 insertions(+), 36 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index e03b112194786..ff7bdb7e7e1a6 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -2611,7 +2611,11 @@ class ASTContext : public RefCountedBase {
   ///
   /// \returns if this is an array type, the completely unqualified array type
   /// that corresponds to it. Otherwise, returns T.getUnqualifiedType().
-  QualType getUnqualifiedArrayType(QualType T, Qualifiers );
+  QualType getUnqualifiedArrayType(QualType T, Qualifiers ) const;
+  QualType getUnqualifiedArrayType(QualType T) const {
+Qualifiers Quals;
+return getUnqualifiedArrayType(T, Quals);
+  }
 
   /// Determine whether the given types are equivalent after
   /// cvr-qualifiers have been removed.
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index da3834f19ca04..df7f396bae095 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1605,6 +1605,10 @@ class QualType {
   QualType stripObjCKindOfType(const ASTContext ) const;
 
   /// Remove all qualifiers including _Atomic.
+  ///
+  /// Like getUnqualifiedType(), the type may still be qualified if it is a
+  /// sugared array type.  To strip qualifiers even from within a sugared array
+  /// type, use ASTContext::getUnqualifiedArrayType.
   QualType getAtomicUnqualifiedType() const;
 
 private:
@@ -2092,8 +2096,8 @@ class alignas(TypeAlignment) Type : public 
ExtQualsTypeCommonBase {
 
 LLVM_PREFERRED_TYPE(TypeBitfields)
 unsigned : NumTypeBits;
-LLVM_PREFERRED_TYPE(bool)
-unsigned IsUnqual : 1; // If true: typeof_unqual, else: typeof
+LLVM_PREFERRED_TYPE(TypeOfKind)
+unsigned Kind : 1;
   };
 
   class UsingBitfields {
@@ -5273,19 +5277,20 @@ class MacroQualifiedType : public Type {
 /// extension) or a `typeof_unqual` expression (a C23 feature).
 class TypeOfExprType : public Type {
   Expr *TOExpr;
+  const ASTContext 
 
 protected:
   friend class ASTContext; // ASTContext creates these.
 
-  TypeOfExprType(Expr *E, TypeOfKind Kind, QualType Can = QualType());
+  TypeOfExprType(const ASTContext , Expr *E, TypeOfKind Kind,
+ QualType Can = QualType());
 
 public:
   Expr *getUnderlyingExpr() const { return TOExpr; }
 
   /// Returns the kind of 'typeof' type this is.
   TypeOfKind getKind() const {
-return TypeOfBits.IsUnqual ? TypeOfKind::Unqualified
-   : TypeOfKind::Qualified;
+return static_cast(TypeOfBits.Kind);
   }
 
   /// Remove a single level of sugar.
@@ -5306,7 +5311,8 @@ class TypeOfExprType : public Type {
 class DependentTypeOfExprType : public TypeOfExprType,
 public llvm::FoldingSetNode {
 public:
-  DependentTypeOfExprType(Expr *E, TypeOfKind Kind) : TypeOfExprType(E, Kind) 
{}
+  DependentTypeOfExprType(const ASTContext , Expr *E, TypeOfKind Kind)
+  : TypeOfExprType(Context, E, Kind) {}
 
   void Profile(llvm::FoldingSetNodeID , const ASTContext ) {
 Profile(ID, Context, getUnderlyingExpr(),
@@ -5323,32 +5329,23 @@ class TypeOfType : public Type {
   friend class ASTContext; // ASTContext creates these.
 
   QualType TOType;
+  const ASTContext 
 
-  TypeOfType(QualType T, QualType Can, TypeOfKind Kind)
-  : Type(TypeOf,
- Kind == TypeOfKind::Unqualified ? Can.getAtomicUnqualifiedType()
- : Can,
- T->getDependence()),
-TOType(T) {
-TypeOfBits.IsUnqual = Kind == TypeOfKind::Unqualified;
-  }
+  TypeOfType(const ASTContext , QualType T, QualType Can,
+ TypeOfKind Kind);
 
 public:
   QualType getUnmodifiedType() const { return TOType; }
 
   /// Remove a single level of sugar.
-  QualType desugar() const {
-QualType QT = getUnmodifiedType();
-return TypeOfBits.IsUnqual ? QT.getAtomicUnqualifiedType() : QT;
-  }
+  QualType desugar() const;
 
   /// Returns whether this type directly provides sugar.
   bool isSugared() const { return true; }
 
   /// Returns the kind of 'typeof' type this is.
   TypeOfKind getKind() const {
-return TypeOfBits.IsUnqual ? TypeOfKind::Unqualified
-   : 

[clang] [Clang] [C23] Fix typeof_unqual for qualified array types (PR #92767)

2024-05-20 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/92767

>From f87cb4c754a477515746e2ac2f8906b93ccd1fe3 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Mon, 20 May 2024 15:58:58 +0100
Subject: [PATCH 1/2] [Clang] [C23] Fix typeof_unqual for qualified array types

Properly remove qualifiers for both the element type and the array type

Fixes #92667
---
 clang/include/clang/AST/ASTContext.h |  6 -
 clang/include/clang/AST/Type.h   | 37 +--
 clang/lib/AST/ASTContext.cpp | 14 +-
 clang/lib/AST/Type.cpp   | 38 ++--
 clang/test/Sema/c2x-typeof.c | 25 ++
 5 files changed, 84 insertions(+), 36 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index e03b112194786..ff7bdb7e7e1a6 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -2611,7 +2611,11 @@ class ASTContext : public RefCountedBase {
   ///
   /// \returns if this is an array type, the completely unqualified array type
   /// that corresponds to it. Otherwise, returns T.getUnqualifiedType().
-  QualType getUnqualifiedArrayType(QualType T, Qualifiers );
+  QualType getUnqualifiedArrayType(QualType T, Qualifiers ) const;
+  QualType getUnqualifiedArrayType(QualType T) const {
+Qualifiers Quals;
+return getUnqualifiedArrayType(T, Quals);
+  }
 
   /// Determine whether the given types are equivalent after
   /// cvr-qualifiers have been removed.
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index da3834f19ca04..df7f396bae095 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1605,6 +1605,10 @@ class QualType {
   QualType stripObjCKindOfType(const ASTContext ) const;
 
   /// Remove all qualifiers including _Atomic.
+  ///
+  /// Like getUnqualifiedType(), the type may still be qualified if it is a
+  /// sugared array type.  To strip qualifiers even from within a sugared array
+  /// type, use ASTContext::getUnqualifiedArrayType.
   QualType getAtomicUnqualifiedType() const;
 
 private:
@@ -2092,8 +2096,8 @@ class alignas(TypeAlignment) Type : public 
ExtQualsTypeCommonBase {
 
 LLVM_PREFERRED_TYPE(TypeBitfields)
 unsigned : NumTypeBits;
-LLVM_PREFERRED_TYPE(bool)
-unsigned IsUnqual : 1; // If true: typeof_unqual, else: typeof
+LLVM_PREFERRED_TYPE(TypeOfKind)
+unsigned Kind : 1;
   };
 
   class UsingBitfields {
@@ -5273,19 +5277,20 @@ class MacroQualifiedType : public Type {
 /// extension) or a `typeof_unqual` expression (a C23 feature).
 class TypeOfExprType : public Type {
   Expr *TOExpr;
+  const ASTContext 
 
 protected:
   friend class ASTContext; // ASTContext creates these.
 
-  TypeOfExprType(Expr *E, TypeOfKind Kind, QualType Can = QualType());
+  TypeOfExprType(const ASTContext , Expr *E, TypeOfKind Kind,
+ QualType Can = QualType());
 
 public:
   Expr *getUnderlyingExpr() const { return TOExpr; }
 
   /// Returns the kind of 'typeof' type this is.
   TypeOfKind getKind() const {
-return TypeOfBits.IsUnqual ? TypeOfKind::Unqualified
-   : TypeOfKind::Qualified;
+return static_cast(TypeOfBits.Kind);
   }
 
   /// Remove a single level of sugar.
@@ -5306,7 +5311,8 @@ class TypeOfExprType : public Type {
 class DependentTypeOfExprType : public TypeOfExprType,
 public llvm::FoldingSetNode {
 public:
-  DependentTypeOfExprType(Expr *E, TypeOfKind Kind) : TypeOfExprType(E, Kind) 
{}
+  DependentTypeOfExprType(const ASTContext , Expr *E, TypeOfKind Kind)
+  : TypeOfExprType(Context, E, Kind) {}
 
   void Profile(llvm::FoldingSetNodeID , const ASTContext ) {
 Profile(ID, Context, getUnderlyingExpr(),
@@ -5323,32 +5329,23 @@ class TypeOfType : public Type {
   friend class ASTContext; // ASTContext creates these.
 
   QualType TOType;
+  const ASTContext 
 
-  TypeOfType(QualType T, QualType Can, TypeOfKind Kind)
-  : Type(TypeOf,
- Kind == TypeOfKind::Unqualified ? Can.getAtomicUnqualifiedType()
- : Can,
- T->getDependence()),
-TOType(T) {
-TypeOfBits.IsUnqual = Kind == TypeOfKind::Unqualified;
-  }
+  TypeOfType(const ASTContext , QualType T, QualType Can,
+ TypeOfKind Kind);
 
 public:
   QualType getUnmodifiedType() const { return TOType; }
 
   /// Remove a single level of sugar.
-  QualType desugar() const {
-QualType QT = getUnmodifiedType();
-return TypeOfBits.IsUnqual ? QT.getAtomicUnqualifiedType() : QT;
-  }
+  QualType desugar() const;
 
   /// Returns whether this type directly provides sugar.
   bool isSugared() const { return true; }
 
   /// Returns the kind of 'typeof' type this is.
   TypeOfKind getKind() const {
-return TypeOfBits.IsUnqual ? TypeOfKind::Unqualified
-   : 

[clang] [Clang] [C23] Fix typeof_unqual for qualified array types (PR #92767)

2024-05-20 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok created 
https://github.com/llvm/llvm-project/pull/92767

Properly remove qualifiers for both the element type and the array type

Fixes #92667

>From f87cb4c754a477515746e2ac2f8906b93ccd1fe3 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Mon, 20 May 2024 15:58:58 +0100
Subject: [PATCH] [Clang] [C23] Fix typeof_unqual for qualified array types

Properly remove qualifiers for both the element type and the array type

Fixes #92667
---
 clang/include/clang/AST/ASTContext.h |  6 -
 clang/include/clang/AST/Type.h   | 37 +--
 clang/lib/AST/ASTContext.cpp | 14 +-
 clang/lib/AST/Type.cpp   | 38 ++--
 clang/test/Sema/c2x-typeof.c | 25 ++
 5 files changed, 84 insertions(+), 36 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index e03b112194786..ff7bdb7e7e1a6 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -2611,7 +2611,11 @@ class ASTContext : public RefCountedBase {
   ///
   /// \returns if this is an array type, the completely unqualified array type
   /// that corresponds to it. Otherwise, returns T.getUnqualifiedType().
-  QualType getUnqualifiedArrayType(QualType T, Qualifiers );
+  QualType getUnqualifiedArrayType(QualType T, Qualifiers ) const;
+  QualType getUnqualifiedArrayType(QualType T) const {
+Qualifiers Quals;
+return getUnqualifiedArrayType(T, Quals);
+  }
 
   /// Determine whether the given types are equivalent after
   /// cvr-qualifiers have been removed.
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index da3834f19ca04..df7f396bae095 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1605,6 +1605,10 @@ class QualType {
   QualType stripObjCKindOfType(const ASTContext ) const;
 
   /// Remove all qualifiers including _Atomic.
+  ///
+  /// Like getUnqualifiedType(), the type may still be qualified if it is a
+  /// sugared array type.  To strip qualifiers even from within a sugared array
+  /// type, use ASTContext::getUnqualifiedArrayType.
   QualType getAtomicUnqualifiedType() const;
 
 private:
@@ -2092,8 +2096,8 @@ class alignas(TypeAlignment) Type : public 
ExtQualsTypeCommonBase {
 
 LLVM_PREFERRED_TYPE(TypeBitfields)
 unsigned : NumTypeBits;
-LLVM_PREFERRED_TYPE(bool)
-unsigned IsUnqual : 1; // If true: typeof_unqual, else: typeof
+LLVM_PREFERRED_TYPE(TypeOfKind)
+unsigned Kind : 1;
   };
 
   class UsingBitfields {
@@ -5273,19 +5277,20 @@ class MacroQualifiedType : public Type {
 /// extension) or a `typeof_unqual` expression (a C23 feature).
 class TypeOfExprType : public Type {
   Expr *TOExpr;
+  const ASTContext 
 
 protected:
   friend class ASTContext; // ASTContext creates these.
 
-  TypeOfExprType(Expr *E, TypeOfKind Kind, QualType Can = QualType());
+  TypeOfExprType(const ASTContext , Expr *E, TypeOfKind Kind,
+ QualType Can = QualType());
 
 public:
   Expr *getUnderlyingExpr() const { return TOExpr; }
 
   /// Returns the kind of 'typeof' type this is.
   TypeOfKind getKind() const {
-return TypeOfBits.IsUnqual ? TypeOfKind::Unqualified
-   : TypeOfKind::Qualified;
+return static_cast(TypeOfBits.Kind);
   }
 
   /// Remove a single level of sugar.
@@ -5306,7 +5311,8 @@ class TypeOfExprType : public Type {
 class DependentTypeOfExprType : public TypeOfExprType,
 public llvm::FoldingSetNode {
 public:
-  DependentTypeOfExprType(Expr *E, TypeOfKind Kind) : TypeOfExprType(E, Kind) 
{}
+  DependentTypeOfExprType(const ASTContext , Expr *E, TypeOfKind Kind)
+  : TypeOfExprType(Context, E, Kind) {}
 
   void Profile(llvm::FoldingSetNodeID , const ASTContext ) {
 Profile(ID, Context, getUnderlyingExpr(),
@@ -5323,32 +5329,23 @@ class TypeOfType : public Type {
   friend class ASTContext; // ASTContext creates these.
 
   QualType TOType;
+  const ASTContext 
 
-  TypeOfType(QualType T, QualType Can, TypeOfKind Kind)
-  : Type(TypeOf,
- Kind == TypeOfKind::Unqualified ? Can.getAtomicUnqualifiedType()
- : Can,
- T->getDependence()),
-TOType(T) {
-TypeOfBits.IsUnqual = Kind == TypeOfKind::Unqualified;
-  }
+  TypeOfType(const ASTContext , QualType T, QualType Can,
+ TypeOfKind Kind);
 
 public:
   QualType getUnmodifiedType() const { return TOType; }
 
   /// Remove a single level of sugar.
-  QualType desugar() const {
-QualType QT = getUnmodifiedType();
-return TypeOfBits.IsUnqual ? QT.getAtomicUnqualifiedType() : QT;
-  }
+  QualType desugar() const;
 
   /// Returns whether this type directly provides sugar.
   bool isSugared() const { return true; }
 
   /// Returns the kind of 'typeof' type this is.
   TypeOfKind getKind() const {
-return 

[clang] [Clang] Add __builtin_is_within_lifetime to implement P2641R4's std::is_within_lifetime (PR #91895)

2024-05-20 Thread Mital Ashok via cfe-commits

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


[clang] [Clang] Add __builtin_is_within_lifetime to implement P2641R4's std::is_within_lifetime (PR #91895)

2024-05-20 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/91895

>From 56aed689dc5825fc5bacc6dfdff58ee0eaf71f82 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 12 May 2024 19:48:24 +0100
Subject: [PATCH 1/9] [Clang] Add attribute for consteval builtins; Declare
 constexpr builtins as constexpr in C++

Also support redeclaring now-constexpr builtins without constexpr
---
 clang/include/clang/Basic/Builtins.h  |  5 +
 clang/include/clang/Basic/BuiltinsBase.td |  2 ++
 clang/lib/Sema/SemaDecl.cpp   | 15 +++
 clang/lib/Sema/SemaDeclCXX.cpp| 18 +-
 clang/lib/Sema/SemaExpr.cpp   |  8 ++--
 clang/test/Sema/builtin-redecl.cpp| 15 ++-
 6 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.h 
b/clang/include/clang/Basic/Builtins.h
index f955d21169556..e85ec5b2dca14 100644
--- a/clang/include/clang/Basic/Builtins.h
+++ b/clang/include/clang/Basic/Builtins.h
@@ -280,6 +280,11 @@ class Context {
 return strchr(getRecord(ID).Attributes, 'E') != nullptr;
   }
 
+  /// Returns true if this is an immediate (consteval) function
+  bool isImmediate(unsigned ID) const {
+return strchr(getRecord(ID).Attributes, 'G') != nullptr;
+  }
+
 private:
   const Info (unsigned ID) const;
 
diff --git a/clang/include/clang/Basic/BuiltinsBase.td 
b/clang/include/clang/Basic/BuiltinsBase.td
index 724747ec76d73..1196b9e15c10d 100644
--- a/clang/include/clang/Basic/BuiltinsBase.td
+++ b/clang/include/clang/Basic/BuiltinsBase.td
@@ -70,6 +70,8 @@ class VScanfFormat : IndexedAttribute<"S", I>;
 
 // Builtin can be constant evaluated
 def Constexpr : Attribute<"E">;
+// Builtin is immediate and must be constant evaluated. Implies Constexpr.
+def Consteval : Attribute<"EG">;
 
 // Builtin kinds
 // =
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index fb913034bd836..6b0a04585928a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2409,10 +2409,17 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, 
QualType Type,
 Parent = CLinkageDecl;
   }
 
-  FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, Type,
-   /*TInfo=*/nullptr, SC_Extern,
-   
getCurFPFeatures().isFPConstrained(),
-   false, Type->isFunctionProtoType());
+  ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified;
+  if (getLangOpts().CPlusPlus && Context.BuiltinInfo.isConstantEvaluated(ID)) {
+ConstexprKind = ConstexprSpecKind::Constexpr;
+if (Context.BuiltinInfo.isImmediate(ID))
+  ConstexprKind = ConstexprSpecKind::Consteval;
+  }
+
+  FunctionDecl *New = FunctionDecl::Create(
+  Context, Parent, Loc, Loc, II, Type, /*TInfo=*/nullptr, SC_Extern,
+  getCurFPFeatures().isFPConstrained(), /*isInlineSpecified=*/false,
+  Type->isFunctionProtoType(), ConstexprKind);
   New->setImplicit();
   New->addAttr(BuiltinAttr::CreateImplicit(Context, ID));
 
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 53238d355ea09..1b558d70f9b48 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -676,11 +676,19 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, 
FunctionDecl *Old,
   // template has a constexpr specifier then all its declarations shall
   // contain the constexpr specifier.
   if (New->getConstexprKind() != Old->getConstexprKind()) {
-Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
-<< New << static_cast(New->getConstexprKind())
-<< static_cast(Old->getConstexprKind());
-Diag(Old->getLocation(), diag::note_previous_declaration);
-Invalid = true;
+if (Old->getBuiltinID() &&
+Old->getConstexprKind() == ConstexprSpecKind::Constexpr &&
+New->getConstexprKind() == ConstexprSpecKind::Unspecified) {
+  // Except allow redeclaring a builtin as non-constexpr to match C
+  // redeclarations which will not be constexpr
+  New->setConstexprKind(ConstexprSpecKind::Constexpr);
+} else {
+  Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
+  << New << static_cast(New->getConstexprKind())
+  << static_cast(Old->getConstexprKind());
+  Diag(Old->getLocation(), diag::note_previous_declaration);
+  Invalid = true;
+}
   } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
  Old->isDefined(Def) &&
  // If a friend function is inlined but does not have 'inline'
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bb4b116fd73ca..39aa32526d2b1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7095,8 +7095,12 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, 
NamedDecl *NDecl,
   }
 
   // Bail out 

[clang] [Clang] Add __builtin_is_within_lifetime to implement P2641R4's std::is_within_lifetime (PR #91895)

2024-05-20 Thread Mital Ashok via cfe-commits

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


[clang] [Clang] Add __builtin_is_within_lifetime to implement P2641R4's std::is_within_lifetime (PR #91895)

2024-05-20 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/91895

>From 56aed689dc5825fc5bacc6dfdff58ee0eaf71f82 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 12 May 2024 19:48:24 +0100
Subject: [PATCH 1/8] [Clang] Add attribute for consteval builtins; Declare
 constexpr builtins as constexpr in C++

Also support redeclaring now-constexpr builtins without constexpr
---
 clang/include/clang/Basic/Builtins.h  |  5 +
 clang/include/clang/Basic/BuiltinsBase.td |  2 ++
 clang/lib/Sema/SemaDecl.cpp   | 15 +++
 clang/lib/Sema/SemaDeclCXX.cpp| 18 +-
 clang/lib/Sema/SemaExpr.cpp   |  8 ++--
 clang/test/Sema/builtin-redecl.cpp| 15 ++-
 6 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.h 
b/clang/include/clang/Basic/Builtins.h
index f955d21169556..e85ec5b2dca14 100644
--- a/clang/include/clang/Basic/Builtins.h
+++ b/clang/include/clang/Basic/Builtins.h
@@ -280,6 +280,11 @@ class Context {
 return strchr(getRecord(ID).Attributes, 'E') != nullptr;
   }
 
+  /// Returns true if this is an immediate (consteval) function
+  bool isImmediate(unsigned ID) const {
+return strchr(getRecord(ID).Attributes, 'G') != nullptr;
+  }
+
 private:
   const Info (unsigned ID) const;
 
diff --git a/clang/include/clang/Basic/BuiltinsBase.td 
b/clang/include/clang/Basic/BuiltinsBase.td
index 724747ec76d73..1196b9e15c10d 100644
--- a/clang/include/clang/Basic/BuiltinsBase.td
+++ b/clang/include/clang/Basic/BuiltinsBase.td
@@ -70,6 +70,8 @@ class VScanfFormat : IndexedAttribute<"S", I>;
 
 // Builtin can be constant evaluated
 def Constexpr : Attribute<"E">;
+// Builtin is immediate and must be constant evaluated. Implies Constexpr.
+def Consteval : Attribute<"EG">;
 
 // Builtin kinds
 // =
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index fb913034bd836..6b0a04585928a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2409,10 +2409,17 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, 
QualType Type,
 Parent = CLinkageDecl;
   }
 
-  FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, Type,
-   /*TInfo=*/nullptr, SC_Extern,
-   
getCurFPFeatures().isFPConstrained(),
-   false, Type->isFunctionProtoType());
+  ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified;
+  if (getLangOpts().CPlusPlus && Context.BuiltinInfo.isConstantEvaluated(ID)) {
+ConstexprKind = ConstexprSpecKind::Constexpr;
+if (Context.BuiltinInfo.isImmediate(ID))
+  ConstexprKind = ConstexprSpecKind::Consteval;
+  }
+
+  FunctionDecl *New = FunctionDecl::Create(
+  Context, Parent, Loc, Loc, II, Type, /*TInfo=*/nullptr, SC_Extern,
+  getCurFPFeatures().isFPConstrained(), /*isInlineSpecified=*/false,
+  Type->isFunctionProtoType(), ConstexprKind);
   New->setImplicit();
   New->addAttr(BuiltinAttr::CreateImplicit(Context, ID));
 
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 53238d355ea09..1b558d70f9b48 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -676,11 +676,19 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, 
FunctionDecl *Old,
   // template has a constexpr specifier then all its declarations shall
   // contain the constexpr specifier.
   if (New->getConstexprKind() != Old->getConstexprKind()) {
-Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
-<< New << static_cast(New->getConstexprKind())
-<< static_cast(Old->getConstexprKind());
-Diag(Old->getLocation(), diag::note_previous_declaration);
-Invalid = true;
+if (Old->getBuiltinID() &&
+Old->getConstexprKind() == ConstexprSpecKind::Constexpr &&
+New->getConstexprKind() == ConstexprSpecKind::Unspecified) {
+  // Except allow redeclaring a builtin as non-constexpr to match C
+  // redeclarations which will not be constexpr
+  New->setConstexprKind(ConstexprSpecKind::Constexpr);
+} else {
+  Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
+  << New << static_cast(New->getConstexprKind())
+  << static_cast(Old->getConstexprKind());
+  Diag(Old->getLocation(), diag::note_previous_declaration);
+  Invalid = true;
+}
   } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
  Old->isDefined(Def) &&
  // If a friend function is inlined but does not have 'inline'
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bb4b116fd73ca..39aa32526d2b1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7095,8 +7095,12 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, 
NamedDecl *NDecl,
   }
 
   // Bail out 

[clang] [Clang][Sema] Fix last argument not being used when comparing function template specializations when one has an explicit object argument (PR #92263)

2024-05-17 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

@Sirraide Oh I didn't see the conflict, thanks. It should be fine now?

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


[clang] [Clang][Sema] Fix last argument not being used when comparing function template specializations when one has an explicit object argument (PR #92263)

2024-05-17 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/92263

>From 6496dbfc8100812c8d3ea5a668af0593b532e4fe Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Wed, 15 May 2024 14:23:17 +0100
Subject: [PATCH 1/2] [Clang][Sema] Fix last argument not being used when
 comparing function template specializations when one has an explicit object
 argument

Fixes #92188
---
 clang/docs/ReleaseNotes.rst|  2 +
 clang/lib/Sema/SemaTemplateDeduction.cpp   |  9 +++-
 clang/test/SemaCXX/cxx2b-deducing-this.cpp | 49 ++
 3 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ae699ebfc6038..9850fc9f8e0b4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -713,6 +713,8 @@ Bug Fixes to C++ Support
 - Correctly treat the compound statement of an ``if consteval`` as an 
immediate context. Fixes (#GH91509).
 - When partial ordering alias templates against template template parameters,
   allow pack expansions when the alias has a fixed-size parameter list. Fixes 
(#GH62529).
+- Fix a bug where the last argument was not considered when considering the 
most viable function for
+  explicit object argument member functions. Fixes (#GH92188).
 
 Bug Fixes to AST Handling
 ^
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 853c0e1b50619..094f767399e2a 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5522,7 +5522,8 @@ static bool isAtLeastAsSpecializedAs(Sema , 
SourceLocation Loc,
 /// function templates.
 ///
 /// \param NumCallArguments1 The number of arguments in the call to FT1, used
-/// only when \c TPOC is \c TPOC_Call.
+/// only when \c TPOC is \c TPOC_Call. Does not include the object argument 
when
+/// calling a member function.
 ///
 /// \param RawObj1Ty The type of the object parameter of FT1 if a member
 /// function only used if \c TPOC is \c TPOC_Call and FT1 is a Function
@@ -5591,7 +5592,11 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
   IsRValRef1);
   Args2.push_back(Obj2Ty);
 }
-size_t NumComparedArguments = NumCallArguments1 + ShouldConvert1;
+size_t NumComparedArguments = NumCallArguments1;
+// Either added an argument above or the prototype includes an explicit
+// object argument we need to count
+if (Method1)
+  ++NumComparedArguments;
 
 Args1.insert(Args1.end(), Proto1->param_type_begin(),
  Proto1->param_type_end());
diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp 
b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index 5f29a955e053c..55792e1448ac5 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -838,3 +838,52 @@ int h() {
   }();
 }
 }
+
+namespace GH92188 {
+struct A {
+  template
+  void operator+=(this auto &&, const char (&)[N]);
+  void operator+=(this auto &&, auto &&) = delete;
+
+  void f1(this A &, auto &);
+  void f1(this A &, auto &&) = delete;
+
+  void f2(this auto&);
+  void f2(this auto&&) = delete;
+
+  void f3(auto&) &;
+  void f3(this A&, auto&&) = delete;
+
+  void f4(auto&&) & = delete;
+  void f4(this A&, auto&);
+
+  static void f5(auto&);
+  void f5(this A&, auto&&) = delete;
+
+  static void f6(auto&&) = delete;
+  void f6(this A&, auto&);
+
+  void implicit_this() {
+int lval;
+operator+=("123");
+f1(lval);
+f2();
+f3(lval);
+f4(lval);
+f5(lval);
+f6(lval);
+  }
+};
+
+void g() {
+  A a;
+  int lval;
+  a += "123";
+  a.f1(lval);
+  a.f2();
+  a.f3(lval);
+  a.f4(lval);
+  a.f5(lval);
+  a.f6(lval);
+}
+}

>From 64e31749874a231956b898e89f00d63790d9f083 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Wed, 15 May 2024 15:05:55 +0100
Subject: [PATCH 2/2] Add test where one template isn't a method

---
 clang/test/SemaCXX/cxx2b-deducing-this.cpp | 8 
 1 file changed, 8 insertions(+)

diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp 
b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index 55792e1448ac5..58372aaff96ea 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -873,6 +873,12 @@ struct A {
 f5(lval);
 f6(lval);
   }
+
+  void operator-(this A&, auto&&) = delete;
+  friend void operator-(A&, auto&);
+
+  void operator*(this A&, auto&);
+  friend void operator*(A&, auto&&) = delete;
 };
 
 void g() {
@@ -885,5 +891,7 @@ void g() {
   a.f4(lval);
   a.f5(lval);
   a.f6(lval);
+  a - lval;
+  a * lval;
 }
 }

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


[clang] [Clang][Sema] Fix last argument not being used when comparing function template specializations when one has an explicit object argument (PR #92263)

2024-05-16 Thread Mital Ashok via cfe-commits


@@ -5591,7 +5592,11 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
   IsRValRef1);
   Args2.push_back(Obj2Ty);
 }
-size_t NumComparedArguments = NumCallArguments1 + ShouldConvert1;
+size_t NumComparedArguments = NumCallArguments1;
+// Either added an argument above or the prototype includes an explicit
+// object argument we need to count
+if (Method1)
+  ++NumComparedArguments;

MitalAshok wrote:

@mizvekov It would look something like this: 
b19a252f50e3b6d5dd50b0e51ec2865bb83fd5c9

But I think it's more error-prone because instead of `+1` in one place, it's 
sometimes a `+1` in all the places `ExplicitCallArguments` is set

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


[clang] [Clang] Fix some assertions not looking through type sugar (PR #92299)

2024-05-15 Thread Mital Ashok via cfe-commits

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


[clang] [Clang] [Sema] Fix some assertions not looking through type sugar (PR #92299)

2024-05-15 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/92299

>From b6cb1c53a20637255bf869617b60155bfb636c60 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Wed, 15 May 2024 18:50:14 +0100
Subject: [PATCH] [Clang] Fix some assertions not looking through type sugar

Fixes #92284
---
 clang/lib/AST/ExprConstant.cpp |  2 +-
 clang/lib/Sema/SemaInit.cpp|  2 +-
 clang/test/SemaCXX/paren-list-agg-init.cpp | 16 
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f1aa19e4409e1..dca2b5d016738 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -11420,7 +11420,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const 
CXXConstructExpr *E,
 
 bool ArrayExprEvaluator::VisitCXXParenListInitExpr(
 const CXXParenListInitExpr *E) {
-  assert(dyn_cast(E->getType()) &&
+  assert(E->getType()->isConstantArrayType() &&
  "Expression result is not a constant array type");
 
   return VisitCXXParenListOrInitListExpr(E, E->getInitExprs(),
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 708286e192f9c..77d0075fbfd88 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5511,7 +5511,7 @@ static void TryOrBuildParenListInitialization(
   << SE->getSourceRange();
   return;
 } else {
-  assert(isa(Entity.getType()));
+  assert(Entity.getType()->isIncompleteArrayType());
   ArrayLength = Args.size();
 }
 EntityIndexToProcess = ArrayLength;
diff --git a/clang/test/SemaCXX/paren-list-agg-init.cpp 
b/clang/test/SemaCXX/paren-list-agg-init.cpp
index c1964a5a9eb00..e8a9cd7e0509c 100644
--- a/clang/test/SemaCXX/paren-list-agg-init.cpp
+++ b/clang/test/SemaCXX/paren-list-agg-init.cpp
@@ -313,3 +313,19 @@ namespace GH63903 {
   constexpr S s(0); // beforecxx20-warning {{aggregate initialization of type 
'const S' from a parenthesized list of values is a C++20 extension}} \
 // expected-error {{constexpr variable 's' must be 
initialized by a constant expression}}
 }
+
+namespace GH92284 {
+  using T = int[1]; T x(42);
+// beforecxx20-warning@-1 {{aggregate initialization of type 'T' (aka 
'int[1]') from a parenthesized list of values is a C++20 extension}}
+  using Ta = int[2]; Ta a(42);
+// beforecxx20-warning@-1 {{aggregate initialization of type 'Ta' (aka 
'int[2]') from a parenthesized list of values is a C++20 extension}}
+  using Tb = int[2]; Tb b(42,43);
+// beforecxx20-warning@-1 {{aggregate initialization of type 'Tb' (aka 
'int[2]') from a parenthesized list of values is a C++20 extension}}
+  using Tc = int[]; Tc c(42);
+// beforecxx20-warning@-1 {{aggregate initialization of type 'int[1]' from a 
parenthesized list of values is a C++20 extension}}
+  using Td = int[]; Td d(42,43);
+// beforecxx20-warning@-1 {{aggregate initialization of type 'int[2]' from a 
parenthesized list of values is a C++20 extension}}
+  template using ThroughAlias = T[Sz];
+  ThroughAlias e(42);
+// beforecxx20-warning@-1 {{aggregate initialization of type 
'ThroughAlias' (aka 'int[1]') from a parenthesized list of values is a 
C++20 extension}}
+}

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


[clang] [Clang] [Sema] Fix some assertions not looking through type sugar (PR #92299)

2024-05-15 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok created 
https://github.com/llvm/llvm-project/pull/92299

Fixes #92284

>From 98d773a3a0a2faa407fddb20a63db7bf01890a98 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Wed, 15 May 2024 18:50:14 +0100
Subject: [PATCH] [Clang] [Sema] Fix some assertions not looking through type
 sugar

Fixes #92284
---
 clang/lib/AST/ExprConstant.cpp |  2 +-
 clang/lib/Sema/SemaInit.cpp|  2 +-
 clang/test/SemaCXX/paren-list-agg-init.cpp | 16 
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f1aa19e4409e1..dca2b5d016738 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -11420,7 +11420,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const 
CXXConstructExpr *E,
 
 bool ArrayExprEvaluator::VisitCXXParenListInitExpr(
 const CXXParenListInitExpr *E) {
-  assert(dyn_cast(E->getType()) &&
+  assert(E->getType()->isConstantArrayType() &&
  "Expression result is not a constant array type");
 
   return VisitCXXParenListOrInitListExpr(E, E->getInitExprs(),
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 708286e192f9c..77d0075fbfd88 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5511,7 +5511,7 @@ static void TryOrBuildParenListInitialization(
   << SE->getSourceRange();
   return;
 } else {
-  assert(isa(Entity.getType()));
+  assert(Entity.getType()->isIncompleteArrayType());
   ArrayLength = Args.size();
 }
 EntityIndexToProcess = ArrayLength;
diff --git a/clang/test/SemaCXX/paren-list-agg-init.cpp 
b/clang/test/SemaCXX/paren-list-agg-init.cpp
index c1964a5a9eb00..e8a9cd7e0509c 100644
--- a/clang/test/SemaCXX/paren-list-agg-init.cpp
+++ b/clang/test/SemaCXX/paren-list-agg-init.cpp
@@ -313,3 +313,19 @@ namespace GH63903 {
   constexpr S s(0); // beforecxx20-warning {{aggregate initialization of type 
'const S' from a parenthesized list of values is a C++20 extension}} \
 // expected-error {{constexpr variable 's' must be 
initialized by a constant expression}}
 }
+
+namespace GH92284 {
+  using T = int[1]; T x(42);
+// beforecxx20-warning@-1 {{aggregate initialization of type 'T' (aka 
'int[1]') from a parenthesized list of values is a C++20 extension}}
+  using Ta = int[2]; Ta a(42);
+// beforecxx20-warning@-1 {{aggregate initialization of type 'Ta' (aka 
'int[2]') from a parenthesized list of values is a C++20 extension}}
+  using Tb = int[2]; Tb b(42,43);
+// beforecxx20-warning@-1 {{aggregate initialization of type 'Tb' (aka 
'int[2]') from a parenthesized list of values is a C++20 extension}}
+  using Tc = int[]; Tc c(42);
+// beforecxx20-warning@-1 {{aggregate initialization of type 'int[1]' from a 
parenthesized list of values is a C++20 extension}}
+  using Td = int[]; Td d(42,43);
+// beforecxx20-warning@-1 {{aggregate initialization of type 'int[2]' from a 
parenthesized list of values is a C++20 extension}}
+  template using ThroughAlias = T[Sz];
+  ThroughAlias e(42);
+// beforecxx20-warning@-1 {{aggregate initialization of type 
'ThroughAlias' (aka 'int[1]') from a parenthesized list of values is a 
C++20 extension}}
+}

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


[clang] [Clang][Sema] Fix last argument not being used when comparing function template specializations when one has an explicit object argument (PR #92263)

2024-05-15 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/92263

>From 6496dbfc8100812c8d3ea5a668af0593b532e4fe Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Wed, 15 May 2024 14:23:17 +0100
Subject: [PATCH 1/2] [Clang][Sema] Fix last argument not being used when
 comparing function template specializations when one has an explicit object
 argument

Fixes #92188
---
 clang/docs/ReleaseNotes.rst|  2 +
 clang/lib/Sema/SemaTemplateDeduction.cpp   |  9 +++-
 clang/test/SemaCXX/cxx2b-deducing-this.cpp | 49 ++
 3 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ae699ebfc6038..9850fc9f8e0b4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -713,6 +713,8 @@ Bug Fixes to C++ Support
 - Correctly treat the compound statement of an ``if consteval`` as an 
immediate context. Fixes (#GH91509).
 - When partial ordering alias templates against template template parameters,
   allow pack expansions when the alias has a fixed-size parameter list. Fixes 
(#GH62529).
+- Fix a bug where the last argument was not considered when considering the 
most viable function for
+  explicit object argument member functions. Fixes (#GH92188).
 
 Bug Fixes to AST Handling
 ^
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 853c0e1b50619..094f767399e2a 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5522,7 +5522,8 @@ static bool isAtLeastAsSpecializedAs(Sema , 
SourceLocation Loc,
 /// function templates.
 ///
 /// \param NumCallArguments1 The number of arguments in the call to FT1, used
-/// only when \c TPOC is \c TPOC_Call.
+/// only when \c TPOC is \c TPOC_Call. Does not include the object argument 
when
+/// calling a member function.
 ///
 /// \param RawObj1Ty The type of the object parameter of FT1 if a member
 /// function only used if \c TPOC is \c TPOC_Call and FT1 is a Function
@@ -5591,7 +5592,11 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
   IsRValRef1);
   Args2.push_back(Obj2Ty);
 }
-size_t NumComparedArguments = NumCallArguments1 + ShouldConvert1;
+size_t NumComparedArguments = NumCallArguments1;
+// Either added an argument above or the prototype includes an explicit
+// object argument we need to count
+if (Method1)
+  ++NumComparedArguments;
 
 Args1.insert(Args1.end(), Proto1->param_type_begin(),
  Proto1->param_type_end());
diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp 
b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index 5f29a955e053c..55792e1448ac5 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -838,3 +838,52 @@ int h() {
   }();
 }
 }
+
+namespace GH92188 {
+struct A {
+  template
+  void operator+=(this auto &&, const char (&)[N]);
+  void operator+=(this auto &&, auto &&) = delete;
+
+  void f1(this A &, auto &);
+  void f1(this A &, auto &&) = delete;
+
+  void f2(this auto&);
+  void f2(this auto&&) = delete;
+
+  void f3(auto&) &;
+  void f3(this A&, auto&&) = delete;
+
+  void f4(auto&&) & = delete;
+  void f4(this A&, auto&);
+
+  static void f5(auto&);
+  void f5(this A&, auto&&) = delete;
+
+  static void f6(auto&&) = delete;
+  void f6(this A&, auto&);
+
+  void implicit_this() {
+int lval;
+operator+=("123");
+f1(lval);
+f2();
+f3(lval);
+f4(lval);
+f5(lval);
+f6(lval);
+  }
+};
+
+void g() {
+  A a;
+  int lval;
+  a += "123";
+  a.f1(lval);
+  a.f2();
+  a.f3(lval);
+  a.f4(lval);
+  a.f5(lval);
+  a.f6(lval);
+}
+}

>From 64e31749874a231956b898e89f00d63790d9f083 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Wed, 15 May 2024 15:05:55 +0100
Subject: [PATCH 2/2] Add test where one template isn't a method

---
 clang/test/SemaCXX/cxx2b-deducing-this.cpp | 8 
 1 file changed, 8 insertions(+)

diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp 
b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index 55792e1448ac5..58372aaff96ea 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -873,6 +873,12 @@ struct A {
 f5(lval);
 f6(lval);
   }
+
+  void operator-(this A&, auto&&) = delete;
+  friend void operator-(A&, auto&);
+
+  void operator*(this A&, auto&);
+  friend void operator*(A&, auto&&) = delete;
 };
 
 void g() {
@@ -885,5 +891,7 @@ void g() {
   a.f4(lval);
   a.f5(lval);
   a.f6(lval);
+  a - lval;
+  a * lval;
 }
 }

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


[clang] [Clang][Sema] Fix last argument not being used when comparing function template specializations when one has an explicit object argument (PR #92263)

2024-05-15 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

See also: #83279

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


[clang] [Clang][Sema] Fix last argument not being used when comparing function template specializations when one has an explicit object argument (PR #92263)

2024-05-15 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok created 
https://github.com/llvm/llvm-project/pull/92263

Fixes #92188

>From 6496dbfc8100812c8d3ea5a668af0593b532e4fe Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Wed, 15 May 2024 14:23:17 +0100
Subject: [PATCH] [Clang][Sema] Fix last argument not being used when comparing
 function template specializations when one has an explicit object argument

Fixes #92188
---
 clang/docs/ReleaseNotes.rst|  2 +
 clang/lib/Sema/SemaTemplateDeduction.cpp   |  9 +++-
 clang/test/SemaCXX/cxx2b-deducing-this.cpp | 49 ++
 3 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ae699ebfc6038..9850fc9f8e0b4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -713,6 +713,8 @@ Bug Fixes to C++ Support
 - Correctly treat the compound statement of an ``if consteval`` as an 
immediate context. Fixes (#GH91509).
 - When partial ordering alias templates against template template parameters,
   allow pack expansions when the alias has a fixed-size parameter list. Fixes 
(#GH62529).
+- Fix a bug where the last argument was not considered when considering the 
most viable function for
+  explicit object argument member functions. Fixes (#GH92188).
 
 Bug Fixes to AST Handling
 ^
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 853c0e1b50619..094f767399e2a 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5522,7 +5522,8 @@ static bool isAtLeastAsSpecializedAs(Sema , 
SourceLocation Loc,
 /// function templates.
 ///
 /// \param NumCallArguments1 The number of arguments in the call to FT1, used
-/// only when \c TPOC is \c TPOC_Call.
+/// only when \c TPOC is \c TPOC_Call. Does not include the object argument 
when
+/// calling a member function.
 ///
 /// \param RawObj1Ty The type of the object parameter of FT1 if a member
 /// function only used if \c TPOC is \c TPOC_Call and FT1 is a Function
@@ -5591,7 +5592,11 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
   IsRValRef1);
   Args2.push_back(Obj2Ty);
 }
-size_t NumComparedArguments = NumCallArguments1 + ShouldConvert1;
+size_t NumComparedArguments = NumCallArguments1;
+// Either added an argument above or the prototype includes an explicit
+// object argument we need to count
+if (Method1)
+  ++NumComparedArguments;
 
 Args1.insert(Args1.end(), Proto1->param_type_begin(),
  Proto1->param_type_end());
diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp 
b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index 5f29a955e053c..55792e1448ac5 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -838,3 +838,52 @@ int h() {
   }();
 }
 }
+
+namespace GH92188 {
+struct A {
+  template
+  void operator+=(this auto &&, const char (&)[N]);
+  void operator+=(this auto &&, auto &&) = delete;
+
+  void f1(this A &, auto &);
+  void f1(this A &, auto &&) = delete;
+
+  void f2(this auto&);
+  void f2(this auto&&) = delete;
+
+  void f3(auto&) &;
+  void f3(this A&, auto&&) = delete;
+
+  void f4(auto&&) & = delete;
+  void f4(this A&, auto&);
+
+  static void f5(auto&);
+  void f5(this A&, auto&&) = delete;
+
+  static void f6(auto&&) = delete;
+  void f6(this A&, auto&);
+
+  void implicit_this() {
+int lval;
+operator+=("123");
+f1(lval);
+f2();
+f3(lval);
+f4(lval);
+f5(lval);
+f6(lval);
+  }
+};
+
+void g() {
+  A a;
+  int lval;
+  a += "123";
+  a.f1(lval);
+  a.f2();
+  a.f3(lval);
+  a.f4(lval);
+  a.f5(lval);
+  a.f6(lval);
+}
+}

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


[clang] [Clang] Add attribute for consteval builtin functions (PR #91894)

2024-05-14 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/91894

>From 56aed689dc5825fc5bacc6dfdff58ee0eaf71f82 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 12 May 2024 19:48:24 +0100
Subject: [PATCH 1/4] [Clang] Add attribute for consteval builtins; Declare
 constexpr builtins as constexpr in C++

Also support redeclaring now-constexpr builtins without constexpr
---
 clang/include/clang/Basic/Builtins.h  |  5 +
 clang/include/clang/Basic/BuiltinsBase.td |  2 ++
 clang/lib/Sema/SemaDecl.cpp   | 15 +++
 clang/lib/Sema/SemaDeclCXX.cpp| 18 +-
 clang/lib/Sema/SemaExpr.cpp   |  8 ++--
 clang/test/Sema/builtin-redecl.cpp| 15 ++-
 6 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.h 
b/clang/include/clang/Basic/Builtins.h
index f955d21169556..e85ec5b2dca14 100644
--- a/clang/include/clang/Basic/Builtins.h
+++ b/clang/include/clang/Basic/Builtins.h
@@ -280,6 +280,11 @@ class Context {
 return strchr(getRecord(ID).Attributes, 'E') != nullptr;
   }
 
+  /// Returns true if this is an immediate (consteval) function
+  bool isImmediate(unsigned ID) const {
+return strchr(getRecord(ID).Attributes, 'G') != nullptr;
+  }
+
 private:
   const Info (unsigned ID) const;
 
diff --git a/clang/include/clang/Basic/BuiltinsBase.td 
b/clang/include/clang/Basic/BuiltinsBase.td
index 724747ec76d73..1196b9e15c10d 100644
--- a/clang/include/clang/Basic/BuiltinsBase.td
+++ b/clang/include/clang/Basic/BuiltinsBase.td
@@ -70,6 +70,8 @@ class VScanfFormat : IndexedAttribute<"S", I>;
 
 // Builtin can be constant evaluated
 def Constexpr : Attribute<"E">;
+// Builtin is immediate and must be constant evaluated. Implies Constexpr.
+def Consteval : Attribute<"EG">;
 
 // Builtin kinds
 // =
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index fb913034bd836..6b0a04585928a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2409,10 +2409,17 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, 
QualType Type,
 Parent = CLinkageDecl;
   }
 
-  FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, Type,
-   /*TInfo=*/nullptr, SC_Extern,
-   
getCurFPFeatures().isFPConstrained(),
-   false, Type->isFunctionProtoType());
+  ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified;
+  if (getLangOpts().CPlusPlus && Context.BuiltinInfo.isConstantEvaluated(ID)) {
+ConstexprKind = ConstexprSpecKind::Constexpr;
+if (Context.BuiltinInfo.isImmediate(ID))
+  ConstexprKind = ConstexprSpecKind::Consteval;
+  }
+
+  FunctionDecl *New = FunctionDecl::Create(
+  Context, Parent, Loc, Loc, II, Type, /*TInfo=*/nullptr, SC_Extern,
+  getCurFPFeatures().isFPConstrained(), /*isInlineSpecified=*/false,
+  Type->isFunctionProtoType(), ConstexprKind);
   New->setImplicit();
   New->addAttr(BuiltinAttr::CreateImplicit(Context, ID));
 
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 53238d355ea09..1b558d70f9b48 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -676,11 +676,19 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, 
FunctionDecl *Old,
   // template has a constexpr specifier then all its declarations shall
   // contain the constexpr specifier.
   if (New->getConstexprKind() != Old->getConstexprKind()) {
-Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
-<< New << static_cast(New->getConstexprKind())
-<< static_cast(Old->getConstexprKind());
-Diag(Old->getLocation(), diag::note_previous_declaration);
-Invalid = true;
+if (Old->getBuiltinID() &&
+Old->getConstexprKind() == ConstexprSpecKind::Constexpr &&
+New->getConstexprKind() == ConstexprSpecKind::Unspecified) {
+  // Except allow redeclaring a builtin as non-constexpr to match C
+  // redeclarations which will not be constexpr
+  New->setConstexprKind(ConstexprSpecKind::Constexpr);
+} else {
+  Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
+  << New << static_cast(New->getConstexprKind())
+  << static_cast(Old->getConstexprKind());
+  Diag(Old->getLocation(), diag::note_previous_declaration);
+  Invalid = true;
+}
   } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
  Old->isDefined(Def) &&
  // If a friend function is inlined but does not have 'inline'
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bb4b116fd73ca..39aa32526d2b1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7095,8 +7095,12 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, 
NamedDecl *NDecl,
   }
 
   // Bail out 

[clang] [Clang] Add attribute for consteval builtin functions (PR #91894)

2024-05-14 Thread Mital Ashok via cfe-commits

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


[clang] [Clang] Add attribute for consteval builtin functions (PR #91894)

2024-05-14 Thread Mital Ashok via cfe-commits

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


[clang] [Clang] Add attribute for consteval builtins; Declare constexpr builtins as constexpr in C++ (PR #91894)

2024-05-14 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/91894

>From 56aed689dc5825fc5bacc6dfdff58ee0eaf71f82 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 12 May 2024 19:48:24 +0100
Subject: [PATCH 1/3] [Clang] Add attribute for consteval builtins; Declare
 constexpr builtins as constexpr in C++

Also support redeclaring now-constexpr builtins without constexpr
---
 clang/include/clang/Basic/Builtins.h  |  5 +
 clang/include/clang/Basic/BuiltinsBase.td |  2 ++
 clang/lib/Sema/SemaDecl.cpp   | 15 +++
 clang/lib/Sema/SemaDeclCXX.cpp| 18 +-
 clang/lib/Sema/SemaExpr.cpp   |  8 ++--
 clang/test/Sema/builtin-redecl.cpp| 15 ++-
 6 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.h 
b/clang/include/clang/Basic/Builtins.h
index f955d21169556..e85ec5b2dca14 100644
--- a/clang/include/clang/Basic/Builtins.h
+++ b/clang/include/clang/Basic/Builtins.h
@@ -280,6 +280,11 @@ class Context {
 return strchr(getRecord(ID).Attributes, 'E') != nullptr;
   }
 
+  /// Returns true if this is an immediate (consteval) function
+  bool isImmediate(unsigned ID) const {
+return strchr(getRecord(ID).Attributes, 'G') != nullptr;
+  }
+
 private:
   const Info (unsigned ID) const;
 
diff --git a/clang/include/clang/Basic/BuiltinsBase.td 
b/clang/include/clang/Basic/BuiltinsBase.td
index 724747ec76d73..1196b9e15c10d 100644
--- a/clang/include/clang/Basic/BuiltinsBase.td
+++ b/clang/include/clang/Basic/BuiltinsBase.td
@@ -70,6 +70,8 @@ class VScanfFormat : IndexedAttribute<"S", I>;
 
 // Builtin can be constant evaluated
 def Constexpr : Attribute<"E">;
+// Builtin is immediate and must be constant evaluated. Implies Constexpr.
+def Consteval : Attribute<"EG">;
 
 // Builtin kinds
 // =
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index fb913034bd836..6b0a04585928a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2409,10 +2409,17 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, 
QualType Type,
 Parent = CLinkageDecl;
   }
 
-  FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, Type,
-   /*TInfo=*/nullptr, SC_Extern,
-   
getCurFPFeatures().isFPConstrained(),
-   false, Type->isFunctionProtoType());
+  ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified;
+  if (getLangOpts().CPlusPlus && Context.BuiltinInfo.isConstantEvaluated(ID)) {
+ConstexprKind = ConstexprSpecKind::Constexpr;
+if (Context.BuiltinInfo.isImmediate(ID))
+  ConstexprKind = ConstexprSpecKind::Consteval;
+  }
+
+  FunctionDecl *New = FunctionDecl::Create(
+  Context, Parent, Loc, Loc, II, Type, /*TInfo=*/nullptr, SC_Extern,
+  getCurFPFeatures().isFPConstrained(), /*isInlineSpecified=*/false,
+  Type->isFunctionProtoType(), ConstexprKind);
   New->setImplicit();
   New->addAttr(BuiltinAttr::CreateImplicit(Context, ID));
 
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 53238d355ea09..1b558d70f9b48 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -676,11 +676,19 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, 
FunctionDecl *Old,
   // template has a constexpr specifier then all its declarations shall
   // contain the constexpr specifier.
   if (New->getConstexprKind() != Old->getConstexprKind()) {
-Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
-<< New << static_cast(New->getConstexprKind())
-<< static_cast(Old->getConstexprKind());
-Diag(Old->getLocation(), diag::note_previous_declaration);
-Invalid = true;
+if (Old->getBuiltinID() &&
+Old->getConstexprKind() == ConstexprSpecKind::Constexpr &&
+New->getConstexprKind() == ConstexprSpecKind::Unspecified) {
+  // Except allow redeclaring a builtin as non-constexpr to match C
+  // redeclarations which will not be constexpr
+  New->setConstexprKind(ConstexprSpecKind::Constexpr);
+} else {
+  Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
+  << New << static_cast(New->getConstexprKind())
+  << static_cast(Old->getConstexprKind());
+  Diag(Old->getLocation(), diag::note_previous_declaration);
+  Invalid = true;
+}
   } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
  Old->isDefined(Def) &&
  // If a friend function is inlined but does not have 'inline'
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bb4b116fd73ca..39aa32526d2b1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7095,8 +7095,12 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, 
NamedDecl *NDecl,
   }
 
   // Bail out 

[clang] [Clang] Add attribute for consteval builtins; Declare constexpr builtins as constexpr in C++ (PR #91894)

2024-05-14 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/91894

>From 56aed689dc5825fc5bacc6dfdff58ee0eaf71f82 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 12 May 2024 19:48:24 +0100
Subject: [PATCH 1/3] [Clang] Add attribute for consteval builtins; Declare
 constexpr builtins as constexpr in C++

Also support redeclaring now-constexpr builtins without constexpr
---
 clang/include/clang/Basic/Builtins.h  |  5 +
 clang/include/clang/Basic/BuiltinsBase.td |  2 ++
 clang/lib/Sema/SemaDecl.cpp   | 15 +++
 clang/lib/Sema/SemaDeclCXX.cpp| 18 +-
 clang/lib/Sema/SemaExpr.cpp   |  8 ++--
 clang/test/Sema/builtin-redecl.cpp| 15 ++-
 6 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.h 
b/clang/include/clang/Basic/Builtins.h
index f955d21169556..e85ec5b2dca14 100644
--- a/clang/include/clang/Basic/Builtins.h
+++ b/clang/include/clang/Basic/Builtins.h
@@ -280,6 +280,11 @@ class Context {
 return strchr(getRecord(ID).Attributes, 'E') != nullptr;
   }
 
+  /// Returns true if this is an immediate (consteval) function
+  bool isImmediate(unsigned ID) const {
+return strchr(getRecord(ID).Attributes, 'G') != nullptr;
+  }
+
 private:
   const Info (unsigned ID) const;
 
diff --git a/clang/include/clang/Basic/BuiltinsBase.td 
b/clang/include/clang/Basic/BuiltinsBase.td
index 724747ec76d73..1196b9e15c10d 100644
--- a/clang/include/clang/Basic/BuiltinsBase.td
+++ b/clang/include/clang/Basic/BuiltinsBase.td
@@ -70,6 +70,8 @@ class VScanfFormat : IndexedAttribute<"S", I>;
 
 // Builtin can be constant evaluated
 def Constexpr : Attribute<"E">;
+// Builtin is immediate and must be constant evaluated. Implies Constexpr.
+def Consteval : Attribute<"EG">;
 
 // Builtin kinds
 // =
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index fb913034bd836..6b0a04585928a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2409,10 +2409,17 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, 
QualType Type,
 Parent = CLinkageDecl;
   }
 
-  FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, Type,
-   /*TInfo=*/nullptr, SC_Extern,
-   
getCurFPFeatures().isFPConstrained(),
-   false, Type->isFunctionProtoType());
+  ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified;
+  if (getLangOpts().CPlusPlus && Context.BuiltinInfo.isConstantEvaluated(ID)) {
+ConstexprKind = ConstexprSpecKind::Constexpr;
+if (Context.BuiltinInfo.isImmediate(ID))
+  ConstexprKind = ConstexprSpecKind::Consteval;
+  }
+
+  FunctionDecl *New = FunctionDecl::Create(
+  Context, Parent, Loc, Loc, II, Type, /*TInfo=*/nullptr, SC_Extern,
+  getCurFPFeatures().isFPConstrained(), /*isInlineSpecified=*/false,
+  Type->isFunctionProtoType(), ConstexprKind);
   New->setImplicit();
   New->addAttr(BuiltinAttr::CreateImplicit(Context, ID));
 
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 53238d355ea09..1b558d70f9b48 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -676,11 +676,19 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, 
FunctionDecl *Old,
   // template has a constexpr specifier then all its declarations shall
   // contain the constexpr specifier.
   if (New->getConstexprKind() != Old->getConstexprKind()) {
-Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
-<< New << static_cast(New->getConstexprKind())
-<< static_cast(Old->getConstexprKind());
-Diag(Old->getLocation(), diag::note_previous_declaration);
-Invalid = true;
+if (Old->getBuiltinID() &&
+Old->getConstexprKind() == ConstexprSpecKind::Constexpr &&
+New->getConstexprKind() == ConstexprSpecKind::Unspecified) {
+  // Except allow redeclaring a builtin as non-constexpr to match C
+  // redeclarations which will not be constexpr
+  New->setConstexprKind(ConstexprSpecKind::Constexpr);
+} else {
+  Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
+  << New << static_cast(New->getConstexprKind())
+  << static_cast(Old->getConstexprKind());
+  Diag(Old->getLocation(), diag::note_previous_declaration);
+  Invalid = true;
+}
   } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
  Old->isDefined(Def) &&
  // If a friend function is inlined but does not have 'inline'
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bb4b116fd73ca..39aa32526d2b1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7095,8 +7095,12 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, 
NamedDecl *NDecl,
   }
 
   // Bail out 

[clang] [Clang] Add attribute for consteval builtins; Declare constexpr builtins as constexpr in C++ (PR #91894)

2024-05-14 Thread Mital Ashok via cfe-commits


@@ -14,13 +14,18 @@ void __builtin_va_copy(double d);
 // expected-error@+2 {{cannot redeclare builtin function '__builtin_va_end'}}
 // expected-note@+1 {{'__builtin_va_end' is a builtin with type}}
 void __builtin_va_end(__builtin_va_list);
-// RUN: %clang_cc1 %s -fsyntax-only -verify 
-// RUN: %clang_cc1 %s -fsyntax-only -verify -x c
 
 void __va_start(__builtin_va_list*, ...);
 
+  void *__builtin_assume_aligned(const void *, size_t, ...);
 #ifdef __cplusplus
-void *__builtin_assume_aligned(const void *, size_t, ...) noexcept;
-#else
-void *__builtin_assume_aligned(const void *, size_t, ...);
+constexpr void *__builtin_assume_aligned(const void *, size_t, ...);
+  void *__builtin_assume_aligned(const void *, size_t, ...) noexcept;
+constexpr void *__builtin_assume_aligned(const void *, size_t, ...) noexcept;
+  void *__builtin_assume_aligned(const void *, size_t, ...) throw();
+constexpr void *__builtin_assume_aligned(const void *, size_t, ...) throw();
+

MitalAshok wrote:

That seems like that should go in a separate patch. For now, I'll change this 
one so `ConstexprSpecKind::Constexpr` isn't added to these builtins as before

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


[clang] [clang] Add tests for CWG issues regarding completeness of types (PR #92113)

2024-05-14 Thread Mital Ashok via cfe-commits

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


[clang] [clang] Add tests for CWG issues regarding completeness of types (PR #92113)

2024-05-14 Thread Mital Ashok via cfe-commits

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


[clang] [clang] Add tests for CWG issues regarding completeness of types (PR #92113)

2024-05-14 Thread Mital Ashok via cfe-commits


@@ -67,6 +63,27 @@ void B::g() requires true;
 
 } // namespace cwg2847
 
+namespace cwg2857 { // cwg2857: 2.7
+struct A {};
+struct B {
+  int operator+(A);
+};
+template 
+struct D;
+
+void f(A* a, D* d) {
+  *d + *a;

MitalAshok wrote:

This wouldn't be an ADL lookup since member functions can't be found via ADL. 
It looks like clang doesn't actually implement CWG2857: 
https://godbolt.org/z/5xdYj7a35 / https://godbolt.org/z/7oqfE5WKW

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


[clang] [llvm] [Clang] Fix definition of layout-compatible to ignore empty classes (PR #92103)

2024-05-14 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/92103

>From 5908130604728b9aa9b70eeb2523d368df08e68d Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Tue, 14 May 2024 08:28:19 +0100
Subject: [PATCH] [Clang] Fix definition of layout-compatible to ignore empty
 classes

Also changes the behaviour of __builtin_is_layout_compatible

None of the historic nor the current definition of layout-compatible classes 
mention anything about base classes (other than implicitly through being 
standard-layout) and are defined in terms of members, not direct members.
---
 clang/include/clang/AST/DeclCXX.h  |  7 
 clang/lib/AST/DeclCXX.cpp  | 36 +
 clang/lib/Sema/SemaChecking.cpp| 63 +-
 clang/test/SemaCXX/type-traits.cpp | 11 ++
 llvm/include/llvm/ADT/STLExtras.h  |  6 +++
 5 files changed, 79 insertions(+), 44 deletions(-)

diff --git a/clang/include/clang/AST/DeclCXX.h 
b/clang/include/clang/AST/DeclCXX.h
index fb52ac804849d..60a5005c51a5e 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1229,6 +1229,13 @@ class CXXRecordDecl : public RecordDecl {
   /// C++11 [class]p7, specifically using the C++11 rules without any DRs.
   bool isCXX11StandardLayout() const { return data().IsCXX11StandardLayout; }
 
+  /// If this is a standard-layout class or union, any and all data members 
will
+  /// be declared in the same type.
+  ///
+  /// This retrieves the type if this class has any data members,
+  /// or the current class if there is no class with fields.
+  const CXXRecordDecl *getStandardLayoutBaseWithFields() const;
+
   /// Determine whether this class, or any of its class subobjects,
   /// contains a mutable field.
   bool hasMutableFields() const { return data().HasMutableFields; }
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 75c441293d62e..ab032a4595d46 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -561,6 +561,42 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl 
*Subobj) {
 data().StructuralIfLiteral = false;
 }
 
+const CXXRecordDecl *CXXRecordDecl::getStandardLayoutBaseWithFields() const {
+#ifndef NDEBUG
+  {
+assert(
+isStandardLayout() &&
+"getStandardLayoutBaseWithFields called on a non-standard-layout 
type");
+unsigned NumberOfBasesWithFields = 0;
+if (!field_empty())
+  ++NumberOfBasesWithFields;
+std::set UniqueBases;
+forallBases([&](const CXXRecordDecl *Base) -> bool {
+  if (!Base->field_empty())
+++NumberOfBasesWithFields;
+  assert(
+  UniqueBases.insert(Base->getCanonicalDecl()).second &&
+  "Standard layout struct has multiple base classes of the same type");
+  return true;
+});
+assert(NumberOfBasesWithFields <= 1 &&
+   "Standard layout struct has fields declared in more than one 
class");
+  }
+#endif
+  if (!field_empty())
+return this;
+  const CXXRecordDecl *Result = this;
+  forallBases([&](const CXXRecordDecl *Base) -> bool {
+if (!Base->field_empty()) {
+  // This is the base where the fields are declared; return early
+  Result = Base;
+  return false;
+}
+return true;
+  });
+  return Result;
+}
+
 bool CXXRecordDecl::hasConstexprDestructor() const {
   auto *Dtor = getDestructor();
   return Dtor ? Dtor->isConstexpr() : defaultedDestructorIsConstexpr();
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ecd1821651140..acd142c1932ad 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -19084,7 +19084,8 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const 
Expr *RHSExpr,
 static bool isLayoutCompatible(ASTContext , QualType T1, QualType T2);
 
 /// Check if two enumeration types are layout-compatible.
-static bool isLayoutCompatible(ASTContext , EnumDecl *ED1, EnumDecl *ED2) {
+static bool isLayoutCompatible(ASTContext , const EnumDecl *ED1,
+   const EnumDecl *ED2) {
   // C++11 [dcl.enum] p8:
   // Two enumeration types are layout-compatible if they have the same
   // underlying type.
@@ -19095,8 +19096,8 @@ static bool isLayoutCompatible(ASTContext , EnumDecl 
*ED1, EnumDecl *ED2) {
 /// Check if two fields are layout-compatible.
 /// Can be used on union members, which are exempt from alignment requirement
 /// of common initial sequence.
-static bool isLayoutCompatible(ASTContext , FieldDecl *Field1,
-   FieldDecl *Field2,
+static bool isLayoutCompatible(ASTContext , const FieldDecl *Field1,
+   const FieldDecl *Field2,
bool AreUnionMembers = false) {
   [[maybe_unused]] const Type *Field1Parent =
   Field1->getParent()->getTypeForDecl();
@@ -19139,52 +19140,26 @@ static bool isLayoutCompatible(ASTContext , 
FieldDecl *Field1,
 
 /// Check if two standard-layout structs 

[clang] [llvm] [Clang] Fix definition of layout-compatible to ignore empty classes (PR #92103)

2024-05-14 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/92103

>From 74e133215e7ba9049fb021eb9bbb130347496503 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Tue, 14 May 2024 08:28:19 +0100
Subject: [PATCH] [Clang] Fix definition of layout-compatible to ignore empty
 classes

Also changes the behaviour of __builtin_is_layout_compatible

None of the historic nor the current definition of layout-compatible classes 
mention anything about base classes (other than implicitly through being 
standard-layout) and are defined in terms of members, not direct members.
---
 clang/include/clang/AST/DeclCXX.h  |  7 
 clang/lib/AST/DeclCXX.cpp  | 36 +
 clang/lib/Sema/SemaChecking.cpp| 63 +-
 clang/test/SemaCXX/type-traits.cpp | 11 ++
 llvm/include/llvm/ADT/STLExtras.h  |  6 +++
 5 files changed, 79 insertions(+), 44 deletions(-)

diff --git a/clang/include/clang/AST/DeclCXX.h 
b/clang/include/clang/AST/DeclCXX.h
index fb52ac804849d..f29592e1e7520 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1229,6 +1229,13 @@ class CXXRecordDecl : public RecordDecl {
   /// C++11 [class]p7, specifically using the C++11 rules without any DRs.
   bool isCXX11StandardLayout() const { return data().IsCXX11StandardLayout; }
 
+  /// If this is a standard-layout class or union per C++11 rules,
+  /// any and all data members will be declared in the same type.
+  ///
+  /// This retrieves the type if this class has any data members,
+  /// or the current class if there is no class with fields.
+  const CXXRecordDecl *getStandardLayoutBaseWithFields() const;
+
   /// Determine whether this class, or any of its class subobjects,
   /// contains a mutable field.
   bool hasMutableFields() const { return data().HasMutableFields; }
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 75c441293d62e..a101b61ad7392 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -561,6 +561,42 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl 
*Subobj) {
 data().StructuralIfLiteral = false;
 }
 
+const CXXRecordDecl *CXXRecordDecl::getStandardLayoutBaseWithFields() const {
+#ifndef NDEBUG
+  {
+assert(
+isCXX11StandardLayout() &&
+"getStandardLayoutBaseWithFields called on a non-standard-layout 
type");
+unsigned NumberOfBasesWithFields = 0;
+if (!field_empty())
+  ++NumberOfBasesWithFields;
+std::set UniqueBases;
+forallBases([&](const CXXRecordDecl *Base) -> bool {
+  if (!Base->field_empty())
+++NumberOfBasesWithFields;
+  assert(
+  UniqueBases.insert(Base->getCanonicalDecl()).second &&
+  "Standard layout struct has multiple base classes of the same type");
+  return true;
+});
+assert(NumberOfBasesWithFields <= 1 &&
+   "Standard layout struct has fields declared in more than one 
class");
+  }
+#endif
+  if (!field_empty())
+return this;
+  const CXXRecordDecl *Result = this;
+  forallBases([&](const CXXRecordDecl *Base) -> bool {
+if (!Base->field_empty()) {
+  // This is the base where the fields are declared; return early
+  Result = Base;
+  return false;
+}
+return true;
+  });
+  return Result;
+}
+
 bool CXXRecordDecl::hasConstexprDestructor() const {
   auto *Dtor = getDestructor();
   return Dtor ? Dtor->isConstexpr() : defaultedDestructorIsConstexpr();
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ecd1821651140..acd142c1932ad 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -19084,7 +19084,8 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const 
Expr *RHSExpr,
 static bool isLayoutCompatible(ASTContext , QualType T1, QualType T2);
 
 /// Check if two enumeration types are layout-compatible.
-static bool isLayoutCompatible(ASTContext , EnumDecl *ED1, EnumDecl *ED2) {
+static bool isLayoutCompatible(ASTContext , const EnumDecl *ED1,
+   const EnumDecl *ED2) {
   // C++11 [dcl.enum] p8:
   // Two enumeration types are layout-compatible if they have the same
   // underlying type.
@@ -19095,8 +19096,8 @@ static bool isLayoutCompatible(ASTContext , EnumDecl 
*ED1, EnumDecl *ED2) {
 /// Check if two fields are layout-compatible.
 /// Can be used on union members, which are exempt from alignment requirement
 /// of common initial sequence.
-static bool isLayoutCompatible(ASTContext , FieldDecl *Field1,
-   FieldDecl *Field2,
+static bool isLayoutCompatible(ASTContext , const FieldDecl *Field1,
+   const FieldDecl *Field2,
bool AreUnionMembers = false) {
   [[maybe_unused]] const Type *Field1Parent =
   Field1->getParent()->getTypeForDecl();
@@ -19139,52 +19140,26 @@ static bool isLayoutCompatible(ASTContext , 
FieldDecl *Field1,
 
 /// Check if two 

[clang] [llvm] [Clang] Fix definition of layout-compatible to ignore empty classes (PR #92103)

2024-05-14 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok created 
https://github.com/llvm/llvm-project/pull/92103

Also changes the behaviour of `__builtin_is_layout_compatible`

None of the historic nor the current definition of layout-compatible classes 
mention anything about base classes (other than implicitly through being 
standard-layout) and are defined in terms of members, not direct members.


>From 147f0a7bb7644bd16584f89e02edbdf4abd81855 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Tue, 14 May 2024 08:28:19 +0100
Subject: [PATCH] [Clang] Fix definition of layout-compatible to ignore empty
 classes

Also changes the behaviour of __builtin_is_layout_compatible

None of the historic nor the current definition of layout-compatible classes 
mention anything about base classes (other than implicitly through being 
standard-layout) and are defined in terms of members, not direct members.
---
 clang/include/clang/AST/DeclCXX.h  |  7 
 clang/lib/AST/DeclCXX.cpp  | 36 +
 clang/lib/Sema/SemaChecking.cpp| 63 +-
 clang/test/SemaCXX/type-traits.cpp | 11 ++
 llvm/include/llvm/ADT/STLExtras.h  |  6 +++
 5 files changed, 79 insertions(+), 44 deletions(-)

diff --git a/clang/include/clang/AST/DeclCXX.h 
b/clang/include/clang/AST/DeclCXX.h
index fb52ac804849d..f29592e1e7520 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1229,6 +1229,13 @@ class CXXRecordDecl : public RecordDecl {
   /// C++11 [class]p7, specifically using the C++11 rules without any DRs.
   bool isCXX11StandardLayout() const { return data().IsCXX11StandardLayout; }
 
+  /// If this is a standard-layout class or union per C++11 rules,
+  /// any and all data members will be declared in the same type.
+  ///
+  /// This retrieves the type if this class has any data members,
+  /// or the current class if there is no class with fields.
+  const CXXRecordDecl *getStandardLayoutBaseWithFields() const;
+
   /// Determine whether this class, or any of its class subobjects,
   /// contains a mutable field.
   bool hasMutableFields() const { return data().HasMutableFields; }
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 75c441293d62e..a101b61ad7392 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -561,6 +561,42 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl 
*Subobj) {
 data().StructuralIfLiteral = false;
 }
 
+const CXXRecordDecl *CXXRecordDecl::getStandardLayoutBaseWithFields() const {
+#ifndef NDEBUG
+  {
+assert(
+isCXX11StandardLayout() &&
+"getStandardLayoutBaseWithFields called on a non-standard-layout 
type");
+unsigned NumberOfBasesWithFields = 0;
+if (!field_empty())
+  ++NumberOfBasesWithFields;
+std::set UniqueBases;
+forallBases([&](const CXXRecordDecl *Base) -> bool {
+  if (!Base->field_empty())
+++NumberOfBasesWithFields;
+  assert(
+  UniqueBases.insert(Base->getCanonicalDecl()).second &&
+  "Standard layout struct has multiple base classes of the same type");
+  return true;
+});
+assert(NumberOfBasesWithFields <= 1 &&
+   "Standard layout struct has fields declared in more than one 
class");
+  }
+#endif
+  if (!field_empty())
+return this;
+  const CXXRecordDecl *Result = this;
+  forallBases([&](const CXXRecordDecl *Base) -> bool {
+if (!Base->field_empty()) {
+  // This is the base where the fields are declared; return early
+  Result = Base;
+  return false;
+}
+return true;
+  });
+  return Result;
+}
+
 bool CXXRecordDecl::hasConstexprDestructor() const {
   auto *Dtor = getDestructor();
   return Dtor ? Dtor->isConstexpr() : defaultedDestructorIsConstexpr();
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ecd1821651140..acd142c1932ad 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -19084,7 +19084,8 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const 
Expr *RHSExpr,
 static bool isLayoutCompatible(ASTContext , QualType T1, QualType T2);
 
 /// Check if two enumeration types are layout-compatible.
-static bool isLayoutCompatible(ASTContext , EnumDecl *ED1, EnumDecl *ED2) {
+static bool isLayoutCompatible(ASTContext , const EnumDecl *ED1,
+   const EnumDecl *ED2) {
   // C++11 [dcl.enum] p8:
   // Two enumeration types are layout-compatible if they have the same
   // underlying type.
@@ -19095,8 +19096,8 @@ static bool isLayoutCompatible(ASTContext , EnumDecl 
*ED1, EnumDecl *ED2) {
 /// Check if two fields are layout-compatible.
 /// Can be used on union members, which are exempt from alignment requirement
 /// of common initial sequence.
-static bool isLayoutCompatible(ASTContext , FieldDecl *Field1,
-   FieldDecl *Field2,
+static bool isLayoutCompatible(ASTContext , const FieldDecl *Field1,
+   

[clang] [Clang] Fix Microsoft ABI inheritance model when member pointer is used in a base specifier (PR #91990)

2024-05-13 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/91990

>From 5dc9193af0d98335a87e93ad70d945dbc0ffce79 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Mon, 13 May 2024 16:59:06 +0100
Subject: [PATCH] [Clang] Fix Microsoft ABI inheritance model when member
 pointer is used in a base specifier

Fix CXXRecordDecl::isParsingBaseSpecifiers so that it is true while parsing 
base specifiers instead of directly after they have been parsed.

-fcomplete-member-pointers now issues a diagnostic when a member pointer is 
used in a base specifier.

-fcomplete-member-pointers has also been relaxed to not issue a diagnostic for 
incomplete classes with an explicit __{single|multiple|virtual}_inheritance 
attribute, whose completeness would not affect the representation of 
pointer-to-member objects.
---
 clang/docs/ReleaseNotes.rst   |  4 +++
 clang/include/clang/AST/DeclCXX.h |  7 +++--
 .../clang/Basic/DiagnosticSemaKinds.td|  2 ++
 clang/lib/AST/DeclCXX.cpp |  6 +
 clang/lib/Parse/ParseDeclCXX.cpp  | 24 +
 clang/lib/Sema/SemaDeclCXX.cpp|  3 ---
 clang/lib/Sema/SemaType.cpp   | 27 ---
 .../test/SemaCXX/complete-member-pointers.cpp | 24 -
 clang/test/SemaCXX/member-pointer-ms.cpp  |  8 ++
 9 files changed, 85 insertions(+), 20 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4702b8c10cdbb..054332c2cee4e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -79,6 +79,10 @@ ABI Changes in This Version
 - Fixed Microsoft calling convention when returning classes that have a deleted
   copy assignment operator. Such a class should be returned indirectly.
 
+- Fixed Microsoft layout of pointer-to-members of classes when the layout is 
needed
+  directly or indirectly by the base classes of a class. These should use the 
most
+  general unspecified inheritance layout. Also affects 
-fcomplete-member-pointers.
+
 AST Dumping Potentially Breaking Changes
 
 
diff --git a/clang/include/clang/AST/DeclCXX.h 
b/clang/include/clang/AST/DeclCXX.h
index fb52ac804849d..81669b1f606b3 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -297,7 +297,8 @@ class CXXRecordDecl : public RecordDecl {
 LLVM_PREFERRED_TYPE(bool)
 unsigned IsLambda : 1;
 
-/// Whether we are currently parsing base specifiers.
+/// Whether we are currently parsing base specifiers; the
+/// colon has been consumed but the beginning left brace hasn't.
 LLVM_PREFERRED_TYPE(bool)
 unsigned IsParsingBaseSpecifiers : 1;
 
@@ -598,7 +599,9 @@ class CXXRecordDecl : public RecordDecl {
 return !hasDefinition() || !isDynamicClass() || hasAnyDependentBases();
   }
 
-  void setIsParsingBaseSpecifiers() { data().IsParsingBaseSpecifiers = true; }
+  void setIsParsingBaseSpecifiers(bool to = true) {
+data().IsParsingBaseSpecifiers = to;
+  }
 
   bool isParsingBaseSpecifiers() const {
 return data().IsParsingBaseSpecifiers;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 9e82130c93609..a9f9f02651cff 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8003,6 +8003,8 @@ def err_bad_memptr_rhs : Error<
 def err_bad_memptr_lhs : Error<
   "left hand operand to %0 must be a %select{|pointer to }1class "
   "compatible with the right hand operand, but is %2">;
+def note_memptr_incomplete_until_bases : Note<
+  "this will affect the ABI of the member pointer until the bases have been 
specified">;
 def err_memptr_incomplete : Error<
   "member pointer has incomplete base type %0">;
 def warn_exception_caught_by_earlier_handler : Warning<
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 75c441293d62e..7f20a47e6a054 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -474,10 +474,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const 
*Bases,
   if (data().IsStandardLayout && NumBases > 1 && hasRepeatedBaseClass(this))
 data().IsStandardLayout = false;
 
-  if (VBases.empty()) {
-data().IsParsingBaseSpecifiers = false;
+  if (VBases.empty())
 return;
-  }
 
   // Create base specifier for any direct or indirect virtual bases.
   data().VBases = new (C) CXXBaseSpecifier[VBases.size()];
@@ -488,8 +486,6 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const 
*Bases,
   addedClassSubobject(Type->getAsCXXRecordDecl());
 data().getVBases()[I] = *VBases[I];
   }
-
-  data().IsParsingBaseSpecifiers = false;
 }
 
 unsigned CXXRecordDecl::getODRHash() const {
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 65ddebca49bc6..a28503b5b4de4 100644
--- 

[clang] [Clang] Fix Microsoft ABI inheritance model when member pointer is used in a base specifier (PR #91990)

2024-05-13 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

Example of the incompatibility: https://godbolt.org/z/Mn1T57WGb

```c++
struct unspecified_inheritance;
template
struct X {
static_assert(I == sizeof(int unspecified_inheritance::*), "");
};

struct Y : X {};
```

Currently, the `sizeof(int Y::*)` locks down the inheritance model of `Y` as 
single, when MSVC marks it as unspecified.

It was the intent that it should have been unspecified:

https://github.com/llvm/llvm-project/blob/89a080cb79972abae240c226090af9a3094e2269/clang/lib/AST/MicrosoftCXXABI.cpp#L223-L224

But `isParsingBaseSpecifiers()` was set after parsing instead of before.

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


[clang] [Clang] Fix Microsoft ABI inheritance model when member pointer is used in a base specifier (PR #91990)

2024-05-13 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok created 
https://github.com/llvm/llvm-project/pull/91990

Fix `CXXRecordDecl::isParsingBaseSpecifiers` so that it is true while parsing 
base specifiers instead of directly after they have been parsed.

-fcomplete-member-pointers now issues a diagnostic when a member pointer is 
used in a base specifier.

-fcomplete-member-pointers has also been relaxed to not issue a diagnostic for 
incomplete classes with an explicit `__{single|multiple|virtual}_inheritance` 
attribute, whose completeness would not affect the representation of 
pointer-to-member objects.

>From a5347082aa47a7aa525ece818f91fb6fdd5fdb0c Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Mon, 13 May 2024 16:59:06 +0100
Subject: [PATCH] [Clang] Fix Microsoft ABI inheritance model when member
 pointer is used in a base specifier

Fix CXXRecordDecl::isParsingBaseSpecifiers so that it is true while parsing 
base specifiers instead of directly after they have been parsed.

-fcomplete-member-pointers now issues a diagnostic when a member pointer is 
used in a base specifier.

-fcomplete-member-pointers has also been relaxed to not issue a diagnostic for 
incomplete classes with an explicit __{single|multiple|virtual}_inheritance 
attribute, whose completeness would not affect the representation of 
pointer-to-member objects.
---
 clang/docs/ReleaseNotes.rst   |  4 
 clang/include/clang/AST/DeclCXX.h |  5 ++--
 .../clang/Basic/DiagnosticSemaKinds.td|  2 ++
 clang/lib/AST/DeclCXX.cpp |  6 +
 clang/lib/Parse/ParseDeclCXX.cpp  | 22 +
 clang/lib/Sema/SemaDeclCXX.cpp|  3 ---
 clang/lib/Sema/SemaType.cpp   | 23 +++---
 .../test/SemaCXX/complete-member-pointers.cpp | 24 ++-
 clang/test/SemaCXX/member-pointer-ms.cpp  |  8 +++
 9 files changed, 77 insertions(+), 20 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4702b8c10cdbb..054332c2cee4e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -79,6 +79,10 @@ ABI Changes in This Version
 - Fixed Microsoft calling convention when returning classes that have a deleted
   copy assignment operator. Such a class should be returned indirectly.
 
+- Fixed Microsoft layout of pointer-to-members of classes when the layout is 
needed
+  directly or indirectly by the base classes of a class. These should use the 
most
+  general unspecified inheritance layout. Also affects 
-fcomplete-member-pointers.
+
 AST Dumping Potentially Breaking Changes
 
 
diff --git a/clang/include/clang/AST/DeclCXX.h 
b/clang/include/clang/AST/DeclCXX.h
index fb52ac804849d..45b3b47ed51c5 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -297,7 +297,8 @@ class CXXRecordDecl : public RecordDecl {
 LLVM_PREFERRED_TYPE(bool)
 unsigned IsLambda : 1;
 
-/// Whether we are currently parsing base specifiers.
+/// Whether we are currently parsing base specifiers; the
+/// colon has been consumed but the beginning left brace hasn't.
 LLVM_PREFERRED_TYPE(bool)
 unsigned IsParsingBaseSpecifiers : 1;
 
@@ -598,7 +599,7 @@ class CXXRecordDecl : public RecordDecl {
 return !hasDefinition() || !isDynamicClass() || hasAnyDependentBases();
   }
 
-  void setIsParsingBaseSpecifiers() { data().IsParsingBaseSpecifiers = true; }
+  void setIsParsingBaseSpecifiers(bool to = true) { 
data().IsParsingBaseSpecifiers = to; }
 
   bool isParsingBaseSpecifiers() const {
 return data().IsParsingBaseSpecifiers;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 9e82130c93609..a9f9f02651cff 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8003,6 +8003,8 @@ def err_bad_memptr_rhs : Error<
 def err_bad_memptr_lhs : Error<
   "left hand operand to %0 must be a %select{|pointer to }1class "
   "compatible with the right hand operand, but is %2">;
+def note_memptr_incomplete_until_bases : Note<
+  "this will affect the ABI of the member pointer until the bases have been 
specified">;
 def err_memptr_incomplete : Error<
   "member pointer has incomplete base type %0">;
 def warn_exception_caught_by_earlier_handler : Warning<
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 75c441293d62e..7f20a47e6a054 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -474,10 +474,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const 
*Bases,
   if (data().IsStandardLayout && NumBases > 1 && hasRepeatedBaseClass(this))
 data().IsStandardLayout = false;
 
-  if (VBases.empty()) {
-data().IsParsingBaseSpecifiers = false;
+  if (VBases.empty())
 return;
-  }
 
   // Create base specifier for any direct or indirect virtual 

[clang] [Clang] Add attribute for consteval builtins; Declare constexpr builtins as constexpr in C++ (PR #91894)

2024-05-13 Thread Mital Ashok via cfe-commits


@@ -14,13 +14,18 @@ void __builtin_va_copy(double d);
 // expected-error@+2 {{cannot redeclare builtin function '__builtin_va_end'}}
 // expected-note@+1 {{'__builtin_va_end' is a builtin with type}}
 void __builtin_va_end(__builtin_va_list);
-// RUN: %clang_cc1 %s -fsyntax-only -verify 
-// RUN: %clang_cc1 %s -fsyntax-only -verify -x c
 
 void __va_start(__builtin_va_list*, ...);
 
+  void *__builtin_assume_aligned(const void *, size_t, ...);
 #ifdef __cplusplus
-void *__builtin_assume_aligned(const void *, size_t, ...) noexcept;
-#else
-void *__builtin_assume_aligned(const void *, size_t, ...);
+constexpr void *__builtin_assume_aligned(const void *, size_t, ...);
+  void *__builtin_assume_aligned(const void *, size_t, ...) noexcept;
+constexpr void *__builtin_assume_aligned(const void *, size_t, ...) noexcept;
+  void *__builtin_assume_aligned(const void *, size_t, ...) throw();
+constexpr void *__builtin_assume_aligned(const void *, size_t, ...) throw();
+

MitalAshok wrote:

For backwards compatibility (and compatibility with the same definitions in C 
or with GCC), to allow declarations with or without the `constexpr`. I suspect 
in any real code, it will always be declared without the `constexpr`.

The other solutions is to keep them all as `ConstexprSpecKind::Unspecified` 
like we currently do, but this is asymmetric with `consteval` builtins which 
will be marked `ConstexprSpecKind::Consteval`, and leads to the builtin 
versions of `std::move`/`std::forward`/constexpr cmath functions to have 
differing `getConstexprKind()` from their non-builtin counterparts



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


[clang] [Clang] Ensure ``if consteval`` consititute an immediate function context (PR #91939)

2024-05-13 Thread Mital Ashok via cfe-commits


@@ -7964,6 +7964,15 @@ TreeTransform::TransformIfStmt(IfStmt *S) {
   // Transform the "then" branch.
   StmtResult Then;
   if (!ConstexprConditionValue || *ConstexprConditionValue) {
+Sema::ExpressionEvaluationContext Context =
+S->isNonNegatedConsteval()
+? Sema::ExpressionEvaluationContext::ImmediateFunctionContext
+: Sema::ExpressionEvaluationContext::PotentiallyEvaluated;
+
+EnterExpressionEvaluationContext Ctx(
+getSema(), Context, nullptr,
+Sema::ExpressionEvaluationContextRecord::EK_Other);

MitalAshok wrote:

```suggestion
EnterExpressionEvaluationContext Ctx(
getSema(), Sema::ExpressionEvaluationContext::ImmediateFunctionContext, 
nullptr,
Sema::ExpressionEvaluationContextRecord::EK_Other,
S->isNonNegatedConsteval());
```

(and ditto for the else branch) to only push a context if needed

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


[clang] [Clang] Add attribute for consteval builtins; Declare constexpr builtins as constexpr in C++ (PR #91894)

2024-05-12 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

Currently, GCC's behaviour for builtin function redeclarations is to just 
ignore `constexpr`: . This is slightly 
stricter, allowing non-`constexpr` redeclarations for `constexpr` builtins but 
still disallowing `constexpr` declarations for non-`constexpr` builtins.

[P2641R4 `std::is_within_lifetime`](https://wg21.link/P2641R4) is most likely 
going to be implemented as a `consteval` builtin, which the attribute allows 
implementing easily as a builtin-function with `getConstexprKind() == 
ConstexprSpecKind::Consteval`.

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


[clang] [Clang] Add __builtin_is_within_lifetime to implement P2641R4's std::is_within_lifetime (PR #91895)

2024-05-12 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

This is on top of #91894

[P2641R4](https://wg21.link/P2641R4)

Currently, this doesn't strictly check "whose complete object's lifetime began 
within `E`". A bunch of the static_asserts I have for objects under 
construction should be ill-formed instead of false, but some of them should be 
true.

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


[clang] [Clang] Add __builtin_is_within_lifetime to implement P2641R4's std::is_within_lifetime (PR #91895)

2024-05-12 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok created 
https://github.com/llvm/llvm-project/pull/91895

None

>From 56aed689dc5825fc5bacc6dfdff58ee0eaf71f82 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 12 May 2024 19:48:24 +0100
Subject: [PATCH 1/2] [Clang] Add attribute for consteval builtins; Declare
 constexpr builtins as constexpr in C++

Also support redeclaring now-constexpr builtins without constexpr
---
 clang/include/clang/Basic/Builtins.h  |  5 +
 clang/include/clang/Basic/BuiltinsBase.td |  2 ++
 clang/lib/Sema/SemaDecl.cpp   | 15 +++
 clang/lib/Sema/SemaDeclCXX.cpp| 18 +-
 clang/lib/Sema/SemaExpr.cpp   |  8 ++--
 clang/test/Sema/builtin-redecl.cpp| 15 ++-
 6 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.h 
b/clang/include/clang/Basic/Builtins.h
index f955d21169556..e85ec5b2dca14 100644
--- a/clang/include/clang/Basic/Builtins.h
+++ b/clang/include/clang/Basic/Builtins.h
@@ -280,6 +280,11 @@ class Context {
 return strchr(getRecord(ID).Attributes, 'E') != nullptr;
   }
 
+  /// Returns true if this is an immediate (consteval) function
+  bool isImmediate(unsigned ID) const {
+return strchr(getRecord(ID).Attributes, 'G') != nullptr;
+  }
+
 private:
   const Info (unsigned ID) const;
 
diff --git a/clang/include/clang/Basic/BuiltinsBase.td 
b/clang/include/clang/Basic/BuiltinsBase.td
index 724747ec76d73..1196b9e15c10d 100644
--- a/clang/include/clang/Basic/BuiltinsBase.td
+++ b/clang/include/clang/Basic/BuiltinsBase.td
@@ -70,6 +70,8 @@ class VScanfFormat : IndexedAttribute<"S", I>;
 
 // Builtin can be constant evaluated
 def Constexpr : Attribute<"E">;
+// Builtin is immediate and must be constant evaluated. Implies Constexpr.
+def Consteval : Attribute<"EG">;
 
 // Builtin kinds
 // =
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index fb913034bd836..6b0a04585928a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2409,10 +2409,17 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, 
QualType Type,
 Parent = CLinkageDecl;
   }
 
-  FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, Type,
-   /*TInfo=*/nullptr, SC_Extern,
-   
getCurFPFeatures().isFPConstrained(),
-   false, Type->isFunctionProtoType());
+  ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified;
+  if (getLangOpts().CPlusPlus && Context.BuiltinInfo.isConstantEvaluated(ID)) {
+ConstexprKind = ConstexprSpecKind::Constexpr;
+if (Context.BuiltinInfo.isImmediate(ID))
+  ConstexprKind = ConstexprSpecKind::Consteval;
+  }
+
+  FunctionDecl *New = FunctionDecl::Create(
+  Context, Parent, Loc, Loc, II, Type, /*TInfo=*/nullptr, SC_Extern,
+  getCurFPFeatures().isFPConstrained(), /*isInlineSpecified=*/false,
+  Type->isFunctionProtoType(), ConstexprKind);
   New->setImplicit();
   New->addAttr(BuiltinAttr::CreateImplicit(Context, ID));
 
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 53238d355ea09..1b558d70f9b48 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -676,11 +676,19 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, 
FunctionDecl *Old,
   // template has a constexpr specifier then all its declarations shall
   // contain the constexpr specifier.
   if (New->getConstexprKind() != Old->getConstexprKind()) {
-Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
-<< New << static_cast(New->getConstexprKind())
-<< static_cast(Old->getConstexprKind());
-Diag(Old->getLocation(), diag::note_previous_declaration);
-Invalid = true;
+if (Old->getBuiltinID() &&
+Old->getConstexprKind() == ConstexprSpecKind::Constexpr &&
+New->getConstexprKind() == ConstexprSpecKind::Unspecified) {
+  // Except allow redeclaring a builtin as non-constexpr to match C
+  // redeclarations which will not be constexpr
+  New->setConstexprKind(ConstexprSpecKind::Constexpr);
+} else {
+  Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
+  << New << static_cast(New->getConstexprKind())
+  << static_cast(Old->getConstexprKind());
+  Diag(Old->getLocation(), diag::note_previous_declaration);
+  Invalid = true;
+}
   } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
  Old->isDefined(Def) &&
  // If a friend function is inlined but does not have 'inline'
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bb4b116fd73ca..39aa32526d2b1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7095,8 +7095,12 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, 
NamedDecl *NDecl,
   }
 
   // Bail 

[clang] [Clang] Add attribute for consteval builtins; Declare constexpr builtins as constexpr in C++ (PR #91894)

2024-05-12 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok created 
https://github.com/llvm/llvm-project/pull/91894

Also support redeclaring now-constexpr builtins without constexpr

>From 56aed689dc5825fc5bacc6dfdff58ee0eaf71f82 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 12 May 2024 19:48:24 +0100
Subject: [PATCH] [Clang] Add attribute for consteval builtins; Declare
 constexpr builtins as constexpr in C++

Also support redeclaring now-constexpr builtins without constexpr
---
 clang/include/clang/Basic/Builtins.h  |  5 +
 clang/include/clang/Basic/BuiltinsBase.td |  2 ++
 clang/lib/Sema/SemaDecl.cpp   | 15 +++
 clang/lib/Sema/SemaDeclCXX.cpp| 18 +-
 clang/lib/Sema/SemaExpr.cpp   |  8 ++--
 clang/test/Sema/builtin-redecl.cpp| 15 ++-
 6 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.h 
b/clang/include/clang/Basic/Builtins.h
index f955d21169556..e85ec5b2dca14 100644
--- a/clang/include/clang/Basic/Builtins.h
+++ b/clang/include/clang/Basic/Builtins.h
@@ -280,6 +280,11 @@ class Context {
 return strchr(getRecord(ID).Attributes, 'E') != nullptr;
   }
 
+  /// Returns true if this is an immediate (consteval) function
+  bool isImmediate(unsigned ID) const {
+return strchr(getRecord(ID).Attributes, 'G') != nullptr;
+  }
+
 private:
   const Info (unsigned ID) const;
 
diff --git a/clang/include/clang/Basic/BuiltinsBase.td 
b/clang/include/clang/Basic/BuiltinsBase.td
index 724747ec76d73..1196b9e15c10d 100644
--- a/clang/include/clang/Basic/BuiltinsBase.td
+++ b/clang/include/clang/Basic/BuiltinsBase.td
@@ -70,6 +70,8 @@ class VScanfFormat : IndexedAttribute<"S", I>;
 
 // Builtin can be constant evaluated
 def Constexpr : Attribute<"E">;
+// Builtin is immediate and must be constant evaluated. Implies Constexpr.
+def Consteval : Attribute<"EG">;
 
 // Builtin kinds
 // =
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index fb913034bd836..6b0a04585928a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2409,10 +2409,17 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, 
QualType Type,
 Parent = CLinkageDecl;
   }
 
-  FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, Type,
-   /*TInfo=*/nullptr, SC_Extern,
-   
getCurFPFeatures().isFPConstrained(),
-   false, Type->isFunctionProtoType());
+  ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified;
+  if (getLangOpts().CPlusPlus && Context.BuiltinInfo.isConstantEvaluated(ID)) {
+ConstexprKind = ConstexprSpecKind::Constexpr;
+if (Context.BuiltinInfo.isImmediate(ID))
+  ConstexprKind = ConstexprSpecKind::Consteval;
+  }
+
+  FunctionDecl *New = FunctionDecl::Create(
+  Context, Parent, Loc, Loc, II, Type, /*TInfo=*/nullptr, SC_Extern,
+  getCurFPFeatures().isFPConstrained(), /*isInlineSpecified=*/false,
+  Type->isFunctionProtoType(), ConstexprKind);
   New->setImplicit();
   New->addAttr(BuiltinAttr::CreateImplicit(Context, ID));
 
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 53238d355ea09..1b558d70f9b48 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -676,11 +676,19 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, 
FunctionDecl *Old,
   // template has a constexpr specifier then all its declarations shall
   // contain the constexpr specifier.
   if (New->getConstexprKind() != Old->getConstexprKind()) {
-Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
-<< New << static_cast(New->getConstexprKind())
-<< static_cast(Old->getConstexprKind());
-Diag(Old->getLocation(), diag::note_previous_declaration);
-Invalid = true;
+if (Old->getBuiltinID() &&
+Old->getConstexprKind() == ConstexprSpecKind::Constexpr &&
+New->getConstexprKind() == ConstexprSpecKind::Unspecified) {
+  // Except allow redeclaring a builtin as non-constexpr to match C
+  // redeclarations which will not be constexpr
+  New->setConstexprKind(ConstexprSpecKind::Constexpr);
+} else {
+  Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
+  << New << static_cast(New->getConstexprKind())
+  << static_cast(Old->getConstexprKind());
+  Diag(Old->getLocation(), diag::note_previous_declaration);
+  Invalid = true;
+}
   } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
  Old->isDefined(Def) &&
  // If a friend function is inlined but does not have 'inline'
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bb4b116fd73ca..39aa32526d2b1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7095,8 +7095,12 @@ ExprResult 

[clang] [analyzer] Allow recursive functions to be trivial. (PR #91876)

2024-05-12 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

You should add a test for mutually recursive functions. I suspect something 
like this doesn't work:

```c++
int non_trivial();
int f(bool b) { return g(!b) + non_trivial(); }
int g(bool b) { return b ? f(b) : 1; }

getFieldTrivial().f(true);  // expected-warning {{...}}
getFieldTrivial().g(true);  // expected-warning {{...}}
```

Since when analyzing `f`, `f` enters the cache as trivial, `g` is analyzed and 
sees `f` in the cache as trivial, so `g` is marked trivial, but then `f` is 
marked as non-trivial (so `g` should have been marked as non-trivial, but is 
marked trivial).

If that is an issue, one way to do this "properly" would be to create a graph, 
and a function is non-trivial if it has a path to a non-trivial function (this 
might be too expensive to implement directly). Or we could special case simple 
recursion only, by changing `TrivialFunctionAnalysisVisitor` to not call 
`isTrivialImpl` for the current function only.

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


[clang] [Clang] No longer require complete types with __builtin_launder (PR #91070)

2024-05-10 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

Here's one scenario where it could make a difference in codegen 
:

```c++
// Header
struct X;
extern X x;
void f(X&);
inline void g() {
f(x);
}
inline void h() {
f(*__builtin_launder(__builtin_addressof(x)));
}

// Source
struct X {
virtual void mem() { __builtin_printf("X::mem()\n"); }
};
void f(X& x) {
x.mem();
}
void(*p[2])() = { g, h };  // Force inline functions to be generated
```

Even though Clang currently doesn't do this optimization, with 
`-fstrict-vtable-pointers`, `g()` is allowed to to devirtualise the call.

Also, we can't "complete" the type at all. See 
,
 where the template is not allowed to be instantiated by `launder`.

Maybe we could delay the code-gen to the end of the TU to see if it's completed 
by then? I do think it's an incredibly rare situation for some incomplete type 
to be `std::launder`ed and then later completed in the same TU.


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


[clang] [Clang] No longer require complete types with __builtin_launder (PR #91070)

2024-05-04 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/91070

>From 11ad517cede0902945c0b7eba0e7f1ff93f08ea0 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sat, 4 May 2024 17:31:31 +0100
Subject: [PATCH] [Clang] No longer require complete types with
 __builtin_launder

Incomplete types are assumed to need the llvm.launder.invariant.group intrinsic

Fixes #90949
---
 clang/docs/ReleaseNotes.rst |  2 +
 clang/lib/CodeGen/CGBuiltin.cpp |  5 +-
 clang/lib/Sema/SemaChecking.cpp | 21 +---
 clang/test/AST/Interp/builtin-functions.cpp | 14 --
 clang/test/CodeGenCXX/builtin-launder.cpp   | 56 +
 clang/test/SemaCXX/builtins.cpp | 14 --
 6 files changed, 85 insertions(+), 27 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 54b58b1ae99fbd..e22a80a6f281c9 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -552,6 +552,8 @@ Bug Fixes in This Version
 - Clang will no longer emit a duplicate -Wunused-value warning for an 
expression
   `(A, B)` which evaluates to glvalue `B` that can be converted to non 
ODR-use. (#GH45783)
 
+- `__builtin_launder` no longer requires a pointer to a complete type. 
(#GH90949)
+
 Bug Fixes to Compiler Builtins
 ^^
 
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 8e31652f4dabef..6a544f97cac5e2 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2487,8 +2487,9 @@ TypeRequiresBuiltinLaunderImp(const ASTContext , 
QualType Ty,
   if (!Seen.insert(Record).second)
 return false;
 
-  assert(Record->hasDefinition() &&
- "Incomplete types should already be diagnosed");
+  // Assume incomplete types need to be laundered
+  if (!Record->hasDefinition())
+return true;
 
   if (Record->isDynamicClass())
 return true;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 3179d542b1f926..9ed404f9e7c936 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2164,15 +2164,8 @@ static ExprResult BuiltinLaunder(Sema , CallExpr 
*TheCall) {
   //  * The type of the argument if it's not an array or function type,
   //  Otherwise,
   //  * The decayed argument type.
-  QualType ParamTy = [&]() {
-QualType ArgTy = TheCall->getArg(0)->getType();
-if (const ArrayType *Ty = ArgTy->getAsArrayTypeUnsafe())
-  return S.Context.getPointerType(Ty->getElementType());
-if (ArgTy->isFunctionType()) {
-  return S.Context.getPointerType(ArgTy);
-}
-return ArgTy;
-  }();
+  QualType ParamTy =
+  S.Context.getAdjustedParameterType(TheCall->getArg(0)->getType());
 
   TheCall->setType(ParamTy);
 
@@ -2191,16 +2184,6 @@ static ExprResult BuiltinLaunder(Sema , CallExpr 
*TheCall) {
 return ExprError();
   }
 
-  // We either have an incomplete class type, or we have a class template
-  // whose instantiation has not been forced. Example:
-  //
-  //   template  struct Foo { T value; };
-  //   Foo *p = nullptr;
-  //   auto *d = __builtin_launder(p);
-  if (S.RequireCompleteType(TheCall->getBeginLoc(), ParamTy->getPointeeType(),
-diag::err_incomplete_type))
-return ExprError();
-
   assert(ParamTy->getPointeeType()->isObjectType() &&
  "Unhandled non-object pointer case");
 
diff --git a/clang/test/AST/Interp/builtin-functions.cpp 
b/clang/test/AST/Interp/builtin-functions.cpp
index 0cbab1fcd91d09..efb2c5f825932e 100644
--- a/clang/test/AST/Interp/builtin-functions.cpp
+++ b/clang/test/AST/Interp/builtin-functions.cpp
@@ -457,16 +457,24 @@ void f() {
   static_assert(test_in_constexpr(i), "");
 }
 
-struct Incomplete; // both-note {{forward declaration}}
+struct Incomplete;
 struct IncompleteMember {
   Incomplete 
 };
 void test_incomplete(Incomplete *i, IncompleteMember *im) {
-  // both-error@+1 {{incomplete type 'Incomplete' where a complete type is 
required}}
-  __builtin_launder(i);
+  __builtin_launder(i); // OK
   __builtin_launder(); // OK
   __builtin_launder(im); // OK
 }
+extern Incomplete incomplete;
+extern IncompleteMember incomplete_member;
+static_assert(test_constexpr_launder() == , "");
+static_assert(test_constexpr_launder(_member) == 
_member, "");
+template struct X { static_assert(false, ""); };
+extern X x;
+static_assert(__builtin_launder(__builtin_addressof(x)) == 
__builtin_addressof(x), "");
+static_assert((test_constexpr_launder)(__builtin_addressof(x)) == 
__builtin_addressof(x), "");
+template<> struct X {};
 
 void test_noexcept(int *i) {
   static_assert(noexcept(__builtin_launder(i)), "");
diff --git a/clang/test/CodeGenCXX/builtin-launder.cpp 
b/clang/test/CodeGenCXX/builtin-launder.cpp
index 06a93d1c441d29..8cfbc3101e30d3 100644
--- a/clang/test/CodeGenCXX/builtin-launder.cpp
+++ b/clang/test/CodeGenCXX/builtin-launder.cpp
@@ -53,10 +53,66 @@ extern "C" void 

[clang] [Clang] No longer require complete types with __builtin_launder (PR #91070)

2024-05-04 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/91070

>From fe8c0dc5f7beacae7b1494a5987c3674dbd330d3 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sat, 4 May 2024 17:31:31 +0100
Subject: [PATCH] [Clang] No longer require complete types with
 __builtin_launder

Incomplete types are assumed to need the llvm.launder.invariant.group intrinsic

Fixes #90949
---
 clang/docs/ReleaseNotes.rst   |  2 +
 clang/lib/CodeGen/CGBuiltin.cpp   |  5 +-
 clang/lib/Sema/SemaChecking.cpp   | 21 +
 clang/test/CodeGenCXX/builtin-launder.cpp | 56 +++
 clang/test/SemaCXX/builtins.cpp   | 14 --
 5 files changed, 74 insertions(+), 24 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 54b58b1ae99fbd..e22a80a6f281c9 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -552,6 +552,8 @@ Bug Fixes in This Version
 - Clang will no longer emit a duplicate -Wunused-value warning for an 
expression
   `(A, B)` which evaluates to glvalue `B` that can be converted to non 
ODR-use. (#GH45783)
 
+- `__builtin_launder` no longer requires a pointer to a complete type. 
(#GH90949)
+
 Bug Fixes to Compiler Builtins
 ^^
 
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 8e31652f4dabef..6a544f97cac5e2 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2487,8 +2487,9 @@ TypeRequiresBuiltinLaunderImp(const ASTContext , 
QualType Ty,
   if (!Seen.insert(Record).second)
 return false;
 
-  assert(Record->hasDefinition() &&
- "Incomplete types should already be diagnosed");
+  // Assume incomplete types need to be laundered
+  if (!Record->hasDefinition())
+return true;
 
   if (Record->isDynamicClass())
 return true;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 3179d542b1f926..9ed404f9e7c936 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2164,15 +2164,8 @@ static ExprResult BuiltinLaunder(Sema , CallExpr 
*TheCall) {
   //  * The type of the argument if it's not an array or function type,
   //  Otherwise,
   //  * The decayed argument type.
-  QualType ParamTy = [&]() {
-QualType ArgTy = TheCall->getArg(0)->getType();
-if (const ArrayType *Ty = ArgTy->getAsArrayTypeUnsafe())
-  return S.Context.getPointerType(Ty->getElementType());
-if (ArgTy->isFunctionType()) {
-  return S.Context.getPointerType(ArgTy);
-}
-return ArgTy;
-  }();
+  QualType ParamTy =
+  S.Context.getAdjustedParameterType(TheCall->getArg(0)->getType());
 
   TheCall->setType(ParamTy);
 
@@ -2191,16 +2184,6 @@ static ExprResult BuiltinLaunder(Sema , CallExpr 
*TheCall) {
 return ExprError();
   }
 
-  // We either have an incomplete class type, or we have a class template
-  // whose instantiation has not been forced. Example:
-  //
-  //   template  struct Foo { T value; };
-  //   Foo *p = nullptr;
-  //   auto *d = __builtin_launder(p);
-  if (S.RequireCompleteType(TheCall->getBeginLoc(), ParamTy->getPointeeType(),
-diag::err_incomplete_type))
-return ExprError();
-
   assert(ParamTy->getPointeeType()->isObjectType() &&
  "Unhandled non-object pointer case");
 
diff --git a/clang/test/CodeGenCXX/builtin-launder.cpp 
b/clang/test/CodeGenCXX/builtin-launder.cpp
index 06a93d1c441d29..8cfbc3101e30d3 100644
--- a/clang/test/CodeGenCXX/builtin-launder.cpp
+++ b/clang/test/CodeGenCXX/builtin-launder.cpp
@@ -53,10 +53,66 @@ extern "C" void 
test_builtin_launder_virtual_base(TestVirtualBase *p) {
   TestVirtualBase *d = __builtin_launder(p);
 }
 
+struct IncompleteNeedsLaunder;
+
+// CHECK-LABEL: define{{.*}} void 
@test_builtin_launder_incomplete_later_needs_launder
+extern "C" void 
test_builtin_launder_incomplete_later_needs_launder(IncompleteNeedsLaunder *p) {
+  // CHECK-STRICT-NOT: ret void
+  // CHECK-STRICT: @llvm.launder.invariant.group
+
+  // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
+
+  // CHECK: ret void
+  IncompleteNeedsLaunder *d = __builtin_launder(p);
+}
+
+struct IncompleteNeedsLaunder {
+  virtual void foo() {}
+};
+
+// CHECK-LABEL: define{{.*}} void @test_builtin_launder_completed_needs_launder
+extern "C" void 
test_builtin_launder_completed_needs_launder(IncompleteNeedsLaunder *p) {
+  // CHECK-STRICT-NOT: ret void
+  // CHECK-STRICT: @llvm.launder.invariant.group
+
+  // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
+
+  // CHECK: ret void
+  IncompleteNeedsLaunder *d = __builtin_launder(p);
+}
+
+struct IncompleteDoesntNeedLaunder;
+
+// CHECK-LABEL: define{{.*}} void 
@test_builtin_launder_incomplete_later_doesnt_needs_launder
+extern "C" void 
test_builtin_launder_incomplete_later_doesnt_needs_launder(IncompleteDoesntNeedLaunder
 *p) {
+  // CHECK-STRICT-NOT: ret void
+  // CHECK-STRICT: 

[clang] [Clang] No longer require complete types with __builtin_launder (PR #91070)

2024-05-04 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok created 
https://github.com/llvm/llvm-project/pull/91070

Incomplete types are assumed to need the llvm.launder.invariant.group intrinsic

Fixes #90949

>From 21d9f27692b2a2fa9ac99f4644109e62e3730133 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sat, 4 May 2024 17:31:31 +0100
Subject: [PATCH] [Clang] No longer require complete types with
 __builtin_launder

Incomplete types are assumed to need the llvm.launder.invariant.group intrinsic

Fixes #90949
---
 clang/docs/ReleaseNotes.rst   |  2 +
 clang/lib/CodeGen/CGBuiltin.cpp   |  5 +-
 clang/lib/Sema/SemaChecking.cpp   | 20 +---
 clang/test/CodeGenCXX/builtin-launder.cpp | 56 +++
 clang/test/SemaCXX/builtins.cpp   | 14 --
 5 files changed, 73 insertions(+), 24 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 54b58b1ae99fbd..e22a80a6f281c9 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -552,6 +552,8 @@ Bug Fixes in This Version
 - Clang will no longer emit a duplicate -Wunused-value warning for an 
expression
   `(A, B)` which evaluates to glvalue `B` that can be converted to non 
ODR-use. (#GH45783)
 
+- `__builtin_launder` no longer requires a pointer to a complete type. 
(#GH90949)
+
 Bug Fixes to Compiler Builtins
 ^^
 
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 8e31652f4dabef..6a544f97cac5e2 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2487,8 +2487,9 @@ TypeRequiresBuiltinLaunderImp(const ASTContext , 
QualType Ty,
   if (!Seen.insert(Record).second)
 return false;
 
-  assert(Record->hasDefinition() &&
- "Incomplete types should already be diagnosed");
+  // Assume incomplete types need to be laundered
+  if (!Record->hasDefinition())
+return true;
 
   if (Record->isDynamicClass())
 return true;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 3179d542b1f926..c2eb5b51975c1a 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2164,15 +2164,7 @@ static ExprResult BuiltinLaunder(Sema , CallExpr 
*TheCall) {
   //  * The type of the argument if it's not an array or function type,
   //  Otherwise,
   //  * The decayed argument type.
-  QualType ParamTy = [&]() {
-QualType ArgTy = TheCall->getArg(0)->getType();
-if (const ArrayType *Ty = ArgTy->getAsArrayTypeUnsafe())
-  return S.Context.getPointerType(Ty->getElementType());
-if (ArgTy->isFunctionType()) {
-  return S.Context.getPointerType(ArgTy);
-}
-return ArgTy;
-  }();
+  QualType ParamTy = 
S.Context.getAdjustedParameterType(TheCall->getArg(0)->getType());
 
   TheCall->setType(ParamTy);
 
@@ -2191,16 +2183,6 @@ static ExprResult BuiltinLaunder(Sema , CallExpr 
*TheCall) {
 return ExprError();
   }
 
-  // We either have an incomplete class type, or we have a class template
-  // whose instantiation has not been forced. Example:
-  //
-  //   template  struct Foo { T value; };
-  //   Foo *p = nullptr;
-  //   auto *d = __builtin_launder(p);
-  if (S.RequireCompleteType(TheCall->getBeginLoc(), ParamTy->getPointeeType(),
-diag::err_incomplete_type))
-return ExprError();
-
   assert(ParamTy->getPointeeType()->isObjectType() &&
  "Unhandled non-object pointer case");
 
diff --git a/clang/test/CodeGenCXX/builtin-launder.cpp 
b/clang/test/CodeGenCXX/builtin-launder.cpp
index 06a93d1c441d29..8cfbc3101e30d3 100644
--- a/clang/test/CodeGenCXX/builtin-launder.cpp
+++ b/clang/test/CodeGenCXX/builtin-launder.cpp
@@ -53,10 +53,66 @@ extern "C" void 
test_builtin_launder_virtual_base(TestVirtualBase *p) {
   TestVirtualBase *d = __builtin_launder(p);
 }
 
+struct IncompleteNeedsLaunder;
+
+// CHECK-LABEL: define{{.*}} void 
@test_builtin_launder_incomplete_later_needs_launder
+extern "C" void 
test_builtin_launder_incomplete_later_needs_launder(IncompleteNeedsLaunder *p) {
+  // CHECK-STRICT-NOT: ret void
+  // CHECK-STRICT: @llvm.launder.invariant.group
+
+  // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
+
+  // CHECK: ret void
+  IncompleteNeedsLaunder *d = __builtin_launder(p);
+}
+
+struct IncompleteNeedsLaunder {
+  virtual void foo() {}
+};
+
+// CHECK-LABEL: define{{.*}} void @test_builtin_launder_completed_needs_launder
+extern "C" void 
test_builtin_launder_completed_needs_launder(IncompleteNeedsLaunder *p) {
+  // CHECK-STRICT-NOT: ret void
+  // CHECK-STRICT: @llvm.launder.invariant.group
+
+  // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
+
+  // CHECK: ret void
+  IncompleteNeedsLaunder *d = __builtin_launder(p);
+}
+
+struct IncompleteDoesntNeedLaunder;
+
+// CHECK-LABEL: define{{.*}} void 
@test_builtin_launder_incomplete_later_doesnt_needs_launder
+extern "C" void 

[clang] [Clang][Sema] Fix incorrect rejection default construction of union with nontrivial member (PR #82407)

2024-05-01 Thread Mital Ashok via cfe-commits


@@ -9442,9 +9442,21 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
 
   int DiagKind = -1;
 
-  if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
-DiagKind = !Decl ? 0 : 1;
-  else if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
+  if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted) {
+if (CSM == Sema::CXXDefaultConstructor && Field &&
+Field->getParent()->isUnion()) {
+  // [class.default.ctor]p2:
+  //   A defaulted default constructor for class X is defined as deleted if
+  //   - X is a union that has a variant member with a non-trivial default
+  // constructor and no variant member of X has a default member
+  // initializer
+  const auto *RD = cast(Field->getParent());
+  if (!RD->hasInClassInitializer())
+DiagKind = !Decl ? 0 : 1;

MitalAshok wrote:

You can refactor it like this: 
https://github.com/MitalAshok/llvm-project/commit/a119d89788c2c642b5a13ea00b2ea649b04a418e
 and I would suggest changing to an enum for readability: 
https://github.com/MitalAshok/llvm-project/commit/38ca82e1a55012e7d37fd8c6d049d1f00bb50835
 (This can then be extracted out into a static function that returns the enum 
and each `DiagKind = ...` can turn into `return ...`, and the `if`/`else if` 
ladder can be dismantled)

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


[clang] [Clang][Sema] Fix incorrect rejection default construction of union with nontrivial member (PR #82407)

2024-05-01 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

This is [CWG2084](https://wg21.link/CWG2084). Could you also add some tests to 
CXX/drs/ so that www/cxx_dr_status.html can be updated?

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


[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)

2024-05-01 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/90725

>From 0793795ba7d5d5974b1403cd6ead0221fc20c5bb Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Wed, 1 May 2024 12:45:54 +0100
Subject: [PATCH 1/3] [Clang] Ensure "=default"ed function can be deleted when
 used as an extension in C++03

Fixes #90605
---
 clang/lib/Sema/SemaDeclCXX.cpp|  4 ++-
 .../SemaCXX/cxx0x-cursory-default-delete.cpp  | 34 +--
 .../SemaCXX/cxx0x-defaulted-functions.cpp | 13 +++
 3 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 157d42c09cfcd8..e3c90c8ee1d644 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9767,7 +9767,9 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD,
 return false;
   CXXRecordDecl *RD = MD->getParent();
   assert(!RD->isDependentType() && "do deletion after instantiation");
-  if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) ||
+  if (!LangOpts.CPlusPlus ||
+  (!LangOpts.CPlusPlus11 && !RD->isLambda() &&
+   !MD->isExplicitlyDefaulted()) ||
   RD->isInvalidDecl())
 return false;
 
diff --git a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp 
b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp
index 6ae146f0d08c7d..f884725a234671 100644
--- a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp
+++ b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -1,4 +1,11 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify %s
+
+#if __cplusplus < 201103L
+#define static_assert _Static_assert
+#define nullptr 0
+#define noexcept throw()
+#endif
 
 struct non_copiable {
   non_copiable(const non_copiable&) = delete; // expected-note {{marked 
deleted here}}
@@ -25,10 +32,12 @@ void fn1 () {
   non_const_copy ncc;
   non_const_copy ncc2 = ncc;
   ncc = ncc2;
+#if __cplusplus >= 201103L
   const non_const_copy cncc{};
+#endif
   const non_const_copy cncc1; // expected-error {{default initialization of an 
object of const type 'const non_const_copy' without a user-provided default 
constructor}}
-  non_const_copy ncc3 = cncc; // expected-error {{no matching}}
-  ncc = cncc; // expected-error {{no viable overloaded}}
+  non_const_copy ncc3 = cncc1; // expected-error {{no matching}}
+  ncc = cncc1; // expected-error {{no viable overloaded}}
 };
 
 struct no_fields { };
@@ -196,7 +205,7 @@ struct except_spec_d_match : except_spec_a, except_spec_b {
 struct S { S(); };
 S::S() __attribute((noreturn)) = default;
 
-using size_t = decltype(sizeof(0));
+using size_t = __SIZE_TYPE__;
 void *operator new(size_t) = delete; // expected-error {{deleted definition 
must be first declaration}} expected-note {{implicit}}
 void operator delete(void *) noexcept = delete; // expected-error {{deleted 
definition must be first declaration}} expected-note {{implicit}}
 
@@ -217,3 +226,22 @@ namespace deleted_overrides_deleted {
   template struct B : A { virtual void f() = delete; };
   template struct B;
 }
+
+namespace GH90605 {
+struct Element {
+Element& operator=(const Element&) = delete; // #GH90605-Element-assign
+};
+
+struct S {
+Element i; // #GH90605-i
+
+S& operator=(const S&) = default;
+// expected-warning@-1 {{explicitly defaulted copy assignment operator is 
implicitly deleted}}
+//   expected-note@#GH90605-i {{copy assignment operator of 'S' is implicitly 
deleted because field 'i' has a deleted copy assignment operator}}
+//   expected-note@#GH90605-Element-assign {{'operator=' has been explicitly 
marked deleted here}}
+//   expected-note@-4 {{replace 'default' with 'delete'}}
+};
+
+static_assert(!__is_trivially_assignable(S&, const S&), "");
+static_assert(!__is_assignable(S&, const S&), "");
+}
diff --git a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp 
b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
index 0c3dd1ea7aa274..30d54920a1a686 100644
--- a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
+++ b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
@@ -1,4 +1,9 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -fcxx-exceptions 
-Wno-deprecated-builtins %s
+// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify 
-fcxx-exceptions -Wno-deprecated-builtins %s
+
+#if __cplusplus < 201103L
+#define static_assert _Static_assert
+#endif
 
 void fn() = default; // expected-error {{only special member}}
 struct foo {
@@ -43,6 +48,7 @@ void tester() {
   b = c;
 }
 
+#if __cplusplus >= 201103L
 template struct S : T {
   constexpr S() = default; // expected-note {{previous declaration is 
here}}
   constexpr S(const S&) = default; // expected-note {{previous declaration is 
here}}
@@ -118,6 +124,7 @@ namespace DefaultedFnExceptionSpec {
 *p = *p; // expected-note {{instantiation of}}
   }
 }
+#endif
 
 namespace PR13527 {
   struct X {
@@ -135,6 

[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)

2024-05-01 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/90725

>From 0793795ba7d5d5974b1403cd6ead0221fc20c5bb Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Wed, 1 May 2024 12:45:54 +0100
Subject: [PATCH 1/2] [Clang] Ensure "=default"ed function can be deleted when
 used as an extension in C++03

Fixes #90605
---
 clang/lib/Sema/SemaDeclCXX.cpp|  4 ++-
 .../SemaCXX/cxx0x-cursory-default-delete.cpp  | 34 +--
 .../SemaCXX/cxx0x-defaulted-functions.cpp | 13 +++
 3 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 157d42c09cfcd8..e3c90c8ee1d644 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9767,7 +9767,9 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD,
 return false;
   CXXRecordDecl *RD = MD->getParent();
   assert(!RD->isDependentType() && "do deletion after instantiation");
-  if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) ||
+  if (!LangOpts.CPlusPlus ||
+  (!LangOpts.CPlusPlus11 && !RD->isLambda() &&
+   !MD->isExplicitlyDefaulted()) ||
   RD->isInvalidDecl())
 return false;
 
diff --git a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp 
b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp
index 6ae146f0d08c7d..f884725a234671 100644
--- a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp
+++ b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -1,4 +1,11 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify %s
+
+#if __cplusplus < 201103L
+#define static_assert _Static_assert
+#define nullptr 0
+#define noexcept throw()
+#endif
 
 struct non_copiable {
   non_copiable(const non_copiable&) = delete; // expected-note {{marked 
deleted here}}
@@ -25,10 +32,12 @@ void fn1 () {
   non_const_copy ncc;
   non_const_copy ncc2 = ncc;
   ncc = ncc2;
+#if __cplusplus >= 201103L
   const non_const_copy cncc{};
+#endif
   const non_const_copy cncc1; // expected-error {{default initialization of an 
object of const type 'const non_const_copy' without a user-provided default 
constructor}}
-  non_const_copy ncc3 = cncc; // expected-error {{no matching}}
-  ncc = cncc; // expected-error {{no viable overloaded}}
+  non_const_copy ncc3 = cncc1; // expected-error {{no matching}}
+  ncc = cncc1; // expected-error {{no viable overloaded}}
 };
 
 struct no_fields { };
@@ -196,7 +205,7 @@ struct except_spec_d_match : except_spec_a, except_spec_b {
 struct S { S(); };
 S::S() __attribute((noreturn)) = default;
 
-using size_t = decltype(sizeof(0));
+using size_t = __SIZE_TYPE__;
 void *operator new(size_t) = delete; // expected-error {{deleted definition 
must be first declaration}} expected-note {{implicit}}
 void operator delete(void *) noexcept = delete; // expected-error {{deleted 
definition must be first declaration}} expected-note {{implicit}}
 
@@ -217,3 +226,22 @@ namespace deleted_overrides_deleted {
   template struct B : A { virtual void f() = delete; };
   template struct B;
 }
+
+namespace GH90605 {
+struct Element {
+Element& operator=(const Element&) = delete; // #GH90605-Element-assign
+};
+
+struct S {
+Element i; // #GH90605-i
+
+S& operator=(const S&) = default;
+// expected-warning@-1 {{explicitly defaulted copy assignment operator is 
implicitly deleted}}
+//   expected-note@#GH90605-i {{copy assignment operator of 'S' is implicitly 
deleted because field 'i' has a deleted copy assignment operator}}
+//   expected-note@#GH90605-Element-assign {{'operator=' has been explicitly 
marked deleted here}}
+//   expected-note@-4 {{replace 'default' with 'delete'}}
+};
+
+static_assert(!__is_trivially_assignable(S&, const S&), "");
+static_assert(!__is_assignable(S&, const S&), "");
+}
diff --git a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp 
b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
index 0c3dd1ea7aa274..30d54920a1a686 100644
--- a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
+++ b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
@@ -1,4 +1,9 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -fcxx-exceptions 
-Wno-deprecated-builtins %s
+// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify 
-fcxx-exceptions -Wno-deprecated-builtins %s
+
+#if __cplusplus < 201103L
+#define static_assert _Static_assert
+#endif
 
 void fn() = default; // expected-error {{only special member}}
 struct foo {
@@ -43,6 +48,7 @@ void tester() {
   b = c;
 }
 
+#if __cplusplus >= 201103L
 template struct S : T {
   constexpr S() = default; // expected-note {{previous declaration is 
here}}
   constexpr S(const S&) = default; // expected-note {{previous declaration is 
here}}
@@ -118,6 +124,7 @@ namespace DefaultedFnExceptionSpec {
 *p = *p; // expected-note {{instantiation of}}
   }
 }
+#endif
 
 namespace PR13527 {
   struct X {
@@ -135,6 

[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)

2024-05-01 Thread Mital Ashok via cfe-commits


@@ -9767,7 +9767,9 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD,
 return false;
   CXXRecordDecl *RD = MD->getParent();
   assert(!RD->isDependentType() && "do deletion after instantiation");
-  if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) ||
+  if (!LangOpts.CPlusPlus ||

MitalAshok wrote:

I wouldn't think so since we have a CXXMethodDecl and CXXRecordDecl. It was 
added with #73376 which changed it from`!CPlusPlus11` when adding C++03 lambdas

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


[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)

2024-05-01 Thread Mital Ashok via cfe-commits

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


[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)

2024-05-01 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/90725

>From 0793795ba7d5d5974b1403cd6ead0221fc20c5bb Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Wed, 1 May 2024 12:45:54 +0100
Subject: [PATCH 1/2] [Clang] Ensure "=default"ed function can be deleted when
 used as an extension in C++03

Fixes #90605
---
 clang/lib/Sema/SemaDeclCXX.cpp|  4 ++-
 .../SemaCXX/cxx0x-cursory-default-delete.cpp  | 34 +--
 .../SemaCXX/cxx0x-defaulted-functions.cpp | 13 +++
 3 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 157d42c09cfcd8..e3c90c8ee1d644 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9767,7 +9767,9 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD,
 return false;
   CXXRecordDecl *RD = MD->getParent();
   assert(!RD->isDependentType() && "do deletion after instantiation");
-  if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) ||
+  if (!LangOpts.CPlusPlus ||
+  (!LangOpts.CPlusPlus11 && !RD->isLambda() &&
+   !MD->isExplicitlyDefaulted()) ||
   RD->isInvalidDecl())
 return false;
 
diff --git a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp 
b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp
index 6ae146f0d08c7d..f884725a234671 100644
--- a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp
+++ b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -1,4 +1,11 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify %s
+
+#if __cplusplus < 201103L
+#define static_assert _Static_assert
+#define nullptr 0
+#define noexcept throw()
+#endif
 
 struct non_copiable {
   non_copiable(const non_copiable&) = delete; // expected-note {{marked 
deleted here}}
@@ -25,10 +32,12 @@ void fn1 () {
   non_const_copy ncc;
   non_const_copy ncc2 = ncc;
   ncc = ncc2;
+#if __cplusplus >= 201103L
   const non_const_copy cncc{};
+#endif
   const non_const_copy cncc1; // expected-error {{default initialization of an 
object of const type 'const non_const_copy' without a user-provided default 
constructor}}
-  non_const_copy ncc3 = cncc; // expected-error {{no matching}}
-  ncc = cncc; // expected-error {{no viable overloaded}}
+  non_const_copy ncc3 = cncc1; // expected-error {{no matching}}
+  ncc = cncc1; // expected-error {{no viable overloaded}}
 };
 
 struct no_fields { };
@@ -196,7 +205,7 @@ struct except_spec_d_match : except_spec_a, except_spec_b {
 struct S { S(); };
 S::S() __attribute((noreturn)) = default;
 
-using size_t = decltype(sizeof(0));
+using size_t = __SIZE_TYPE__;
 void *operator new(size_t) = delete; // expected-error {{deleted definition 
must be first declaration}} expected-note {{implicit}}
 void operator delete(void *) noexcept = delete; // expected-error {{deleted 
definition must be first declaration}} expected-note {{implicit}}
 
@@ -217,3 +226,22 @@ namespace deleted_overrides_deleted {
   template struct B : A { virtual void f() = delete; };
   template struct B;
 }
+
+namespace GH90605 {
+struct Element {
+Element& operator=(const Element&) = delete; // #GH90605-Element-assign
+};
+
+struct S {
+Element i; // #GH90605-i
+
+S& operator=(const S&) = default;
+// expected-warning@-1 {{explicitly defaulted copy assignment operator is 
implicitly deleted}}
+//   expected-note@#GH90605-i {{copy assignment operator of 'S' is implicitly 
deleted because field 'i' has a deleted copy assignment operator}}
+//   expected-note@#GH90605-Element-assign {{'operator=' has been explicitly 
marked deleted here}}
+//   expected-note@-4 {{replace 'default' with 'delete'}}
+};
+
+static_assert(!__is_trivially_assignable(S&, const S&), "");
+static_assert(!__is_assignable(S&, const S&), "");
+}
diff --git a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp 
b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
index 0c3dd1ea7aa274..30d54920a1a686 100644
--- a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
+++ b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
@@ -1,4 +1,9 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -fcxx-exceptions 
-Wno-deprecated-builtins %s
+// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify 
-fcxx-exceptions -Wno-deprecated-builtins %s
+
+#if __cplusplus < 201103L
+#define static_assert _Static_assert
+#endif
 
 void fn() = default; // expected-error {{only special member}}
 struct foo {
@@ -43,6 +48,7 @@ void tester() {
   b = c;
 }
 
+#if __cplusplus >= 201103L
 template struct S : T {
   constexpr S() = default; // expected-note {{previous declaration is 
here}}
   constexpr S(const S&) = default; // expected-note {{previous declaration is 
here}}
@@ -118,6 +124,7 @@ namespace DefaultedFnExceptionSpec {
 *p = *p; // expected-note {{instantiation of}}
   }
 }
+#endif
 
 namespace PR13527 {
   struct X {
@@ -135,6 

[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)

2024-05-01 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok created 
https://github.com/llvm/llvm-project/pull/90725

Fixes #90605

>From 0793795ba7d5d5974b1403cd6ead0221fc20c5bb Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Wed, 1 May 2024 12:45:54 +0100
Subject: [PATCH] [Clang] Ensure "=default"ed function can be deleted when used
 as an extension in C++03

Fixes #90605
---
 clang/lib/Sema/SemaDeclCXX.cpp|  4 ++-
 .../SemaCXX/cxx0x-cursory-default-delete.cpp  | 34 +--
 .../SemaCXX/cxx0x-defaulted-functions.cpp | 13 +++
 3 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 157d42c09cfcd8..e3c90c8ee1d644 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9767,7 +9767,9 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD,
 return false;
   CXXRecordDecl *RD = MD->getParent();
   assert(!RD->isDependentType() && "do deletion after instantiation");
-  if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) ||
+  if (!LangOpts.CPlusPlus ||
+  (!LangOpts.CPlusPlus11 && !RD->isLambda() &&
+   !MD->isExplicitlyDefaulted()) ||
   RD->isInvalidDecl())
 return false;
 
diff --git a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp 
b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp
index 6ae146f0d08c7d..f884725a234671 100644
--- a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp
+++ b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -1,4 +1,11 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify %s
+
+#if __cplusplus < 201103L
+#define static_assert _Static_assert
+#define nullptr 0
+#define noexcept throw()
+#endif
 
 struct non_copiable {
   non_copiable(const non_copiable&) = delete; // expected-note {{marked 
deleted here}}
@@ -25,10 +32,12 @@ void fn1 () {
   non_const_copy ncc;
   non_const_copy ncc2 = ncc;
   ncc = ncc2;
+#if __cplusplus >= 201103L
   const non_const_copy cncc{};
+#endif
   const non_const_copy cncc1; // expected-error {{default initialization of an 
object of const type 'const non_const_copy' without a user-provided default 
constructor}}
-  non_const_copy ncc3 = cncc; // expected-error {{no matching}}
-  ncc = cncc; // expected-error {{no viable overloaded}}
+  non_const_copy ncc3 = cncc1; // expected-error {{no matching}}
+  ncc = cncc1; // expected-error {{no viable overloaded}}
 };
 
 struct no_fields { };
@@ -196,7 +205,7 @@ struct except_spec_d_match : except_spec_a, except_spec_b {
 struct S { S(); };
 S::S() __attribute((noreturn)) = default;
 
-using size_t = decltype(sizeof(0));
+using size_t = __SIZE_TYPE__;
 void *operator new(size_t) = delete; // expected-error {{deleted definition 
must be first declaration}} expected-note {{implicit}}
 void operator delete(void *) noexcept = delete; // expected-error {{deleted 
definition must be first declaration}} expected-note {{implicit}}
 
@@ -217,3 +226,22 @@ namespace deleted_overrides_deleted {
   template struct B : A { virtual void f() = delete; };
   template struct B;
 }
+
+namespace GH90605 {
+struct Element {
+Element& operator=(const Element&) = delete; // #GH90605-Element-assign
+};
+
+struct S {
+Element i; // #GH90605-i
+
+S& operator=(const S&) = default;
+// expected-warning@-1 {{explicitly defaulted copy assignment operator is 
implicitly deleted}}
+//   expected-note@#GH90605-i {{copy assignment operator of 'S' is implicitly 
deleted because field 'i' has a deleted copy assignment operator}}
+//   expected-note@#GH90605-Element-assign {{'operator=' has been explicitly 
marked deleted here}}
+//   expected-note@-4 {{replace 'default' with 'delete'}}
+};
+
+static_assert(!__is_trivially_assignable(S&, const S&), "");
+static_assert(!__is_assignable(S&, const S&), "");
+}
diff --git a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp 
b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
index 0c3dd1ea7aa274..30d54920a1a686 100644
--- a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
+++ b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
@@ -1,4 +1,9 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -fcxx-exceptions 
-Wno-deprecated-builtins %s
+// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify 
-fcxx-exceptions -Wno-deprecated-builtins %s
+
+#if __cplusplus < 201103L
+#define static_assert _Static_assert
+#endif
 
 void fn() = default; // expected-error {{only special member}}
 struct foo {
@@ -43,6 +48,7 @@ void tester() {
   b = c;
 }
 
+#if __cplusplus >= 201103L
 template struct S : T {
   constexpr S() = default; // expected-note {{previous declaration is 
here}}
   constexpr S(const S&) = default; // expected-note {{previous declaration is 
here}}
@@ -118,6 +124,7 @@ namespace DefaultedFnExceptionSpec {
 *p = *p; // expected-note {{instantiation of}}
   }
 }
+#endif
 
 namespace PR13527 {
   struct X {
@@ 

[clang] [Clang] [C++26] Implement P2573R2: `= delete("should have a reason");` (PR #86526)

2024-05-01 Thread Mital Ashok via cfe-commits


@@ -2280,18 +2294,18 @@ class FunctionDecl : public DeclaratorDecl,
 
   /// Returns whether this specific declaration of the function has a body.
   bool doesThisDeclarationHaveABody() const {
-return (!FunctionDeclBits.HasDefaultedFunctionInfo && Body) ||
+return (!FunctionDeclBits.HasDefaultedOrDeletedInfo && Body) ||
isLateTemplateParsed();
   }
 
   void setBody(Stmt *B);
   void setLazyBody(uint64_t Offset) {
-FunctionDeclBits.HasDefaultedFunctionInfo = false;
+FunctionDeclBits.HasDefaultedOrDeletedInfo = false;
 Body = LazyDeclStmtPtr(Offset);
   }
 
-  void setDefaultedFunctionInfo(DefaultedFunctionInfo *Info);
-  DefaultedFunctionInfo *getDefaultedFunctionInfo() const;
+  void setDefaultedOrDeletedInfo(DefaultedOrDeletedFunctionInfo *Info);
+  DefaultedOrDeletedFunctionInfo *getDefalutedOrDeletedInfo() const;

MitalAshok wrote:

@Sirraide There's no reason we can't change this name to fix this typo right?

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


[clang] [clang] Implement CWG2851: floating-point conversions in converted constant expressions (PR #90387)

2024-04-30 Thread Mital Ashok via cfe-commits


@@ -67,6 +68,69 @@ void B::g() requires true;
 
 } // namespace cwg2847
 
+namespace cwg2851 { // cwg2851: 19
+
+#if __cplusplus >= 202002L
+template struct Val { static constexpr T value = v; };
+
+
+// Floating-point promotions
+
+static_assert(Val::value == 0.0L);
+static_assert(Val::value == 0.0L);
+static_assert(Val::value == 0.0);
+static_assert(Val::value == -0.0L);
+
+static_assert(!__is_same(Val, Val));
+static_assert(__is_same(Val, Val));
+
+static_assert(__is_same(Val, Val));
+
+static_assert(__is_same(Val, Val(__builtin_nanf(""))>));
+static_assert(__is_same(Val, Val(__builtin_nansf(""))>));
+static_assert(__is_same(Val, Val(__builtin_nanf("0x1"))>));
+static_assert(__is_same(Val, Val(__builtin_nansf("0x1"))>));
+
+
+// Floating-point conversions where the source value can be represented 
exactly in the destination type
+
+static_assert(Val::value == 0.0L);
+static_assert(__is_same(Val, Val));
+static_assert(__is_same(Val, Val));
+static_assert(!__is_same(Val, Val));
+static_assert(__is_same(Val, Val));
+static_assert(__is_same(Val, Val));
+
+static_assert(__is_same(Val, Val));
+Val _1;
+// since-cxx20-error-re@-1 {{non-type template argument evaluates to {{.+}} 
which cannot be exactly represented in type 'float'}}
+Val(__FLT_DENORM_MIN__) / 2.0L> _2;
+// since-cxx20-error-re@-1 {{non-type template argument evaluates to {{.+}} 
which cannot be exactly represented in type 'float'}}
+Val _3;
+// since-cxx20-error-re@-1 {{non-type template argument evaluates to {{.+}} 
which cannot be exactly represented in type 'float'}}
+
+static_assert(__is_same(Val, Val));
+
+static_assert(__is_same(Val, Val(__builtin_nanl(""))>));
+static_assert(__is_same(Val, Val(__builtin_nansl(""))>));
+#if __SIZEOF_LONG_DOUBLE__ > 8
+// since-cxx20-error@-2 {{non-type template argument evaluates to nan which 
cannot be exactly represented in type 'float'}}
+#endif
+// Payload is shifted right so these payloads will be preserved
+static_assert(__is_same(Val, Val(__builtin_nan("0xFF"))>));
+static_assert(__is_same(Val, Val(__builtin_nans("0xFF"))>));
+static_assert(__is_same(Val, Val(__builtin_nanl("0x1"))>));

MitalAshok wrote:

I'm not sure how exactly we plan to deal with `NaN`. How `APFloat::convert` 
seems to work is that when converting to a smaller type, only the most 
significant bits of the payload are used, so that 1 is cut off (thus lossy).

This has the side effect that `Val` and `Val` always work, because `(long double) 
__builtin_nanf(payload)` is like `__builtin_nanl(payload << (difference in 
number of fraction bits between long double and float))`, and anything with the 
lower bits set counts as "lossy". Anything implicitly converted to a larger 
type can be converted back in a converted constant expression. See also: 
IEEE754 6.2.3 "NaN propagation"

CWG2864 is about narrowing conversions. For sure `float{__builtin_nanl("0x1")}` 
isn't a narrowing conversion because it's not finite, but it does lose the 
payload entirely (`float{__builtin_nanl("0x1")}` and 
`float{__builtin_nanl("0x0")}` have the same bit pattern, even though the 
source long doubles don't). But maybe we should consider all NaNs to have the 
same "value" and this should work?

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


[clang] [clang] Implement CWG2851: floating-point conversions in converted constant expressions (PR #90387)

2024-04-29 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/90387

>From 77cb28e6faf95f5beb3fadc225cb5f0525b3dfe6 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 28 Apr 2024 09:48:47 +0100
Subject: [PATCH] [clang] Implement CWG2851: floating-point conversions in
 converted constant expressions

---
 clang/docs/ReleaseNotes.rst   |  3 +
 .../clang/Basic/DiagnosticSemaKinds.td|  4 ++
 clang/lib/Sema/SemaOverload.cpp   | 38 ++-
 clang/test/CXX/drs/dr28xx.cpp | 64 +++
 clang/www/cxx_dr_status.html  |  2 +-
 5 files changed, 107 insertions(+), 4 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 604782ca43dd54..6fb0b2d1030be8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -166,6 +166,9 @@ Resolutions to C++ Defect Reports
 - Clang now diagnoses declarative nested-name-specifiers with 
pack-index-specifiers.
   (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers 
`_).
 
+- Allow floating-point promotions and conversions in converted constant 
expressions.
+  (`CWG2851 Allow floating-point conversions in converted constant expressions 
`_).
+
 C Language Changes
 --
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdca82934cb4dc..cb248f2ea6374b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -85,6 +85,10 @@ def err_expr_not_cce : Error<
   "%select{case value|enumerator value|non-type template argument|"
   "array size|explicit specifier argument|noexcept specifier argument|"
   "call to 'size()'|call to 'data()'}0 is not a constant expression">;
+def err_float_conv_cant_represent : Error<
+  "non-type template argument evaluates to %0 which cannot be "
+  "exactly represented in type %1"
+>;
 def ext_cce_narrowing : ExtWarn<
   "%select{case value|enumerator value|non-type template argument|"
   "array size|explicit specifier argument|noexcept specifier argument|"
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 04cd9e78739d20..40d65638e3afc1 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -6072,6 +6072,10 @@ static bool CheckConvertedConstantConversions(Sema ,
   case ICK_Integral_Promotion:
   case ICK_Integral_Conversion: // Narrowing conversions are checked elsewhere.
   case ICK_Zero_Queue_Conversion:
+  // Per CWG2851, floating-point promotions and conversions are allowed.
+  // The value of a conversion is checked afterwards.
+  case ICK_Floating_Promotion:
+  case ICK_Floating_Conversion:
 return true;
 
   case ICK_Boolean_Conversion:
@@ -6091,9 +6095,7 @@ static bool CheckConvertedConstantConversions(Sema ,
 // only permitted if the source type is std::nullptr_t.
 return SCS.getFromType()->isNullPtrType();
 
-  case ICK_Floating_Promotion:
   case ICK_Complex_Promotion:
-  case ICK_Floating_Conversion:
   case ICK_Complex_Conversion:
   case ICK_Floating_Integral:
   case ICK_Compatible_Conversion:
@@ -6229,7 +6231,37 @@ static ExprResult BuildConvertedConstantExpression(Sema 
, Expr *From,
   if (Result.isInvalid())
 return Result;
 
-  // Check for a narrowing implicit conversion.
+  if (SCS->Second == ICK_Floating_Conversion) {
+// Unlike with narrowing conversions, the value must fit
+// exactly even if it is in range
+assert(CCE == Sema::CCEKind::CCEK_TemplateArg &&
+   "Only non-type template args should use floating-point 
conversions");
+
+// Initializer is From, except it is a full-expression
+const Expr *Initializer =
+IgnoreNarrowingConversion(S.Context, Result.get());
+
+// If it's value-dependent, we can't tell whether it will fit
+if (Initializer->isValueDependent())
+  return Result;
+
+// Not-constant diagnosed afterwards
+if (!Initializer->isCXX11ConstantExpr(S.Context, ))
+  return Result;
+
+llvm::APFloat PostNarrowingValue = PreNarrowingValue.getFloat();
+bool LosesInfo = true;
+PostNarrowingValue.convert(S.Context.getFloatTypeSemantics(T),
+   llvm::APFloat::rmNearestTiesToEven, );
+
+if (LosesInfo)
+  S.Diag(From->getBeginLoc(), diag::err_float_conv_cant_represent)
+  << PreNarrowingValue.getAsString(S.Context, From->getType()) << T;
+
+return Result;
+  }
+
+  // Check for a narrowing integer conversion.
   bool ReturnPreNarrowingValue = false;
   QualType PreNarrowingType;
   switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue,
diff --git a/clang/test/CXX/drs/dr28xx.cpp b/clang/test/CXX/drs/dr28xx.cpp
index be35d366bdd614..9076598da14185 100644
--- a/clang/test/CXX/drs/dr28xx.cpp
+++ 

[clang] [Clang] Reuse tail-padding for more types that are not POD for the purpose of layout (PR #90462)

2024-04-29 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

Some choices I've made:

 * Removed `TargetCXXABI::TailPaddingUseRules` and 
`TargetCXXABI::getTailPaddingUseRules()`. Now there are 5 distinct tail padding 
rules (7 if you count tail padding rules that change with 
`-fclang-abi-compat=18.0`), and it was only used in the `mustSkipTailPadding` 
function anyways.
  * Ignored a comment that the Clang WebAssembley ABI should ignore bit-field 
sizes. I don't think that was actually true, but it didn't matter before 
because we didn't check bit-field sizes.
   * `AppleARM64`/`WatchOS`/`iOS` don't skip tail padding for types with 
potentially-overlapping members as well as the oversized bit-fields they were 
documented to ignore.
   * `XL` and `Fuchsia` are also unchanged, for no particular reason other than 
I could not find what the ABI for C++ layout was supposed to be

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


[clang] [Clang] Reuse tail-padding for more types that are not POD for the purpose of layout (PR #90462)

2024-04-29 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok created 
https://github.com/llvm/llvm-project/pull/90462

This will be done for types with over-large bitfields and 
potentially-overlapping ([[no_unique_address]]) members

Compatible with old Clang 18 semantics with -fclang-abi-compat

Fixes #50766

>From 96ff21d5126ebb4b9a538b8eef11f8ac9e2194c5 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Mon, 29 Apr 2024 12:27:04 +0100
Subject: [PATCH] [Clang] Reuse tail-padding for more types that are not POD
 for the purpose of layout

This will be done for types with over-large bitfields and 
potentially-overlapping ([[no_unique_address]]) members

Compatible with old Clang 18 semantics with -fclang-abi-compat

Fixes #50766
---
 clang/docs/ReleaseNotes.rst |   3 +
 clang/include/clang/Basic/LangOptions.h |   4 +-
 clang/include/clang/Basic/TargetCXXABI.h|  51 
 clang/lib/AST/RecordLayoutBuilder.cpp   | 134 +++-
 clang/test/CodeGenCXX/bitfield-layout.cpp   |  20 ++-
 clang/test/CodeGenCXX/no-unique-address.cpp |   9 +-
 clang/test/Layout/no-unique-address.cpp |  20 ++-
 7 files changed, 138 insertions(+), 103 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 604782ca43dd54..b5d76c95a24bd1 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -63,6 +63,9 @@ ABI Changes in This Version
   MSVC uses a different mangling for these objects, compatibility is not 
affected.
   (#GH85423).
 
+- Fixed tail padding not being reused on types with oversized bit-fields and
+  potentially-overlapping members (#GH50766).
+
 AST Dumping Potentially Breaking Changes
 
 
diff --git a/clang/include/clang/Basic/LangOptions.h 
b/clang/include/clang/Basic/LangOptions.h
index e2a2aa71b880b3..3fe1362a2d767e 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -233,7 +233,9 @@ class LangOptionsBase {
 
 /// Attempt to be ABI-compatible with code generated by Clang 18.0.x.
 /// This causes clang to revert some fixes to the mangling of lambdas
-/// in the initializers of members of local classes.
+/// in the initializers of members of local classes and will not reuse
+/// tail padding on structs with potentially-overlapping members or
+/// oversized bit-fields under Itanium and some derived ABIs.
 Ver18,
 
 /// Conform to the underlying platform's C and C++ ABIs as closely
diff --git a/clang/include/clang/Basic/TargetCXXABI.h 
b/clang/include/clang/Basic/TargetCXXABI.h
index c113a6a048ad44..45d9dcc8f1b8a8 100644
--- a/clang/include/clang/Basic/TargetCXXABI.h
+++ b/clang/include/clang/Basic/TargetCXXABI.h
@@ -255,57 +255,6 @@ class TargetCXXABI {
 llvm_unreachable("bad ABI kind");
   }
 
-  /// When is record layout allowed to allocate objects in the tail
-  /// padding of a base class?
-  ///
-  /// This decision cannot be changed without breaking platform ABI
-  /// compatibility. In ISO C++98, tail padding reuse was only permitted for
-  /// non-POD base classes, but that restriction was removed retroactively by
-  /// DR 43, and tail padding reuse is always permitted in all de facto C++
-  /// language modes. However, many platforms use a variant of the old C++98
-  /// rule for compatibility.
-  enum TailPaddingUseRules {
-/// The tail-padding of a base class is always theoretically
-/// available, even if it's POD.
-AlwaysUseTailPadding,
-
-/// Only allocate objects in the tail padding of a base class if
-/// the base class is not POD according to the rules of C++ TR1.
-UseTailPaddingUnlessPOD03,
-
-/// Only allocate objects in the tail padding of a base class if
-/// the base class is not POD according to the rules of C++11.
-UseTailPaddingUnlessPOD11
-  };
-  TailPaddingUseRules getTailPaddingUseRules() const {
-switch (getKind()) {
-// To preserve binary compatibility, the generic Itanium ABI has
-// permanently locked the definition of POD to the rules of C++ TR1,
-// and that trickles down to derived ABIs.
-case GenericItanium:
-case GenericAArch64:
-case GenericARM:
-case iOS:
-case GenericMIPS:
-case XL:
-  return UseTailPaddingUnlessPOD03;
-
-// AppleARM64 and WebAssembly use the C++11 POD rules.  They do not honor
-// the Itanium exception about classes with over-large bitfields.
-case AppleARM64:
-case Fuchsia:
-case WebAssembly:
-case WatchOS:
-  return UseTailPaddingUnlessPOD11;
-
-// MSVC always allocates fields in the tail-padding of a base class
-// subobject, even if they're POD.
-case Microsoft:
-  return AlwaysUseTailPadding;
-}
-llvm_unreachable("bad ABI kind");
-  }
-
   friend bool operator==(const TargetCXXABI , const TargetCXXABI ) {
 return left.getKind() == right.getKind();
   }
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp 

[clang] [clang] Implement CWG2851: floating-point conversions in converted constant expressions (PR #90387)

2024-04-29 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/90387

>From 0b8176cf2171da0ce780c15131e19a24473a6989 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 28 Apr 2024 09:48:47 +0100
Subject: [PATCH] [clang] Implement CWG2851: floating-point conversions in
 converted constant expressions

---
 clang/docs/ReleaseNotes.rst   |  3 +
 .../clang/Basic/DiagnosticSemaKinds.td|  4 ++
 clang/lib/Sema/SemaOverload.cpp   | 38 ++-
 clang/test/CXX/drs/dr28xx.cpp | 64 +++
 clang/www/cxx_dr_status.html  |  2 +-
 5 files changed, 107 insertions(+), 4 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 604782ca43dd54..6fb0b2d1030be8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -166,6 +166,9 @@ Resolutions to C++ Defect Reports
 - Clang now diagnoses declarative nested-name-specifiers with 
pack-index-specifiers.
   (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers 
`_).
 
+- Allow floating-point promotions and conversions in converted constant 
expressions.
+  (`CWG2851 Allow floating-point conversions in converted constant expressions 
`_).
+
 C Language Changes
 --
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdca82934cb4dc..cb248f2ea6374b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -85,6 +85,10 @@ def err_expr_not_cce : Error<
   "%select{case value|enumerator value|non-type template argument|"
   "array size|explicit specifier argument|noexcept specifier argument|"
   "call to 'size()'|call to 'data()'}0 is not a constant expression">;
+def err_float_conv_cant_represent : Error<
+  "non-type template argument evaluates to %0 which cannot be "
+  "exactly represented in type %1"
+>;
 def ext_cce_narrowing : ExtWarn<
   "%select{case value|enumerator value|non-type template argument|"
   "array size|explicit specifier argument|noexcept specifier argument|"
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 04cd9e78739d20..40d65638e3afc1 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -6072,6 +6072,10 @@ static bool CheckConvertedConstantConversions(Sema ,
   case ICK_Integral_Promotion:
   case ICK_Integral_Conversion: // Narrowing conversions are checked elsewhere.
   case ICK_Zero_Queue_Conversion:
+  // Per CWG2851, floating-point promotions and conversions are allowed.
+  // The value of a conversion is checked afterwards.
+  case ICK_Floating_Promotion:
+  case ICK_Floating_Conversion:
 return true;
 
   case ICK_Boolean_Conversion:
@@ -6091,9 +6095,7 @@ static bool CheckConvertedConstantConversions(Sema ,
 // only permitted if the source type is std::nullptr_t.
 return SCS.getFromType()->isNullPtrType();
 
-  case ICK_Floating_Promotion:
   case ICK_Complex_Promotion:
-  case ICK_Floating_Conversion:
   case ICK_Complex_Conversion:
   case ICK_Floating_Integral:
   case ICK_Compatible_Conversion:
@@ -6229,7 +6231,37 @@ static ExprResult BuildConvertedConstantExpression(Sema 
, Expr *From,
   if (Result.isInvalid())
 return Result;
 
-  // Check for a narrowing implicit conversion.
+  if (SCS->Second == ICK_Floating_Conversion) {
+// Unlike with narrowing conversions, the value must fit
+// exactly even if it is in range
+assert(CCE == Sema::CCEKind::CCEK_TemplateArg &&
+   "Only non-type template args should use floating-point 
conversions");
+
+// Initializer is From, except it is a full-expression
+const Expr *Initializer =
+IgnoreNarrowingConversion(S.Context, Result.get());
+
+// If it's value-dependent, we can't tell whether it will fit
+if (Initializer->isValueDependent())
+  return Result;
+
+// Not-constant diagnosed afterwards
+if (!Initializer->isCXX11ConstantExpr(S.Context, ))
+  return Result;
+
+llvm::APFloat PostNarrowingValue = PreNarrowingValue.getFloat();
+bool LosesInfo = true;
+PostNarrowingValue.convert(S.Context.getFloatTypeSemantics(T),
+   llvm::APFloat::rmNearestTiesToEven, );
+
+if (LosesInfo)
+  S.Diag(From->getBeginLoc(), diag::err_float_conv_cant_represent)
+  << PreNarrowingValue.getAsString(S.Context, From->getType()) << T;
+
+return Result;
+  }
+
+  // Check for a narrowing integer conversion.
   bool ReturnPreNarrowingValue = false;
   QualType PreNarrowingType;
   switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue,
diff --git a/clang/test/CXX/drs/dr28xx.cpp b/clang/test/CXX/drs/dr28xx.cpp
index 1967e8b751db2d..e0a180a1df27f3 100644
--- a/clang/test/CXX/drs/dr28xx.cpp
+++ 

[clang] [clang] Implement CWG2851: floating-point conversions in converted constant expressions (PR #90387)

2024-04-29 Thread Mital Ashok via cfe-commits


@@ -6229,7 +6231,37 @@ static ExprResult BuildConvertedConstantExpression(Sema 
, Expr *From,
   if (Result.isInvalid())
 return Result;
 
-  // Check for a narrowing implicit conversion.
+  if (SCS->Second == ICK_Floating_Conversion) {

MitalAshok wrote:

Because it has a different specification from narrowing conversions 
( vs ), 
so we need stuff specific for converted constant expressions. E.g., 
`float{__FLT_DENORM_MIN__ / 4.0}` is not a narrowing conversion even though it 
rounds the double value to `0.0f`, but it shouldn't be a converted constant 
expression.

Theoretically we should only be calling `getNarrowingKind` when `SCS->Second == 
ICK_Integral_Conversion` (I think we also use it for boolean conversions 
[CWG1407](https://cplusplus.github.io/CWG/issues/1407.html)).

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


[clang] [clang] Implement CWG2851: floating-point conversions in converted constant expressions (PR #90387)

2024-04-28 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

Waiting on #90352 because it's not on the cxx_dr_status page yet 
(`make_dr_status` doesn't do anything)

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


[clang] [clang] Implement CWG2851: floating-point conversions in converted constant expressions (PR #90387)

2024-04-28 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/90387

>From 13e2943dea677daf8976ab55a673d43982ac8a4c Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 28 Apr 2024 09:48:47 +0100
Subject: [PATCH] [clang] Implement CWG2851: floating-point conversions in
 converted constant expressions

---
 clang/docs/ReleaseNotes.rst   |  3 +
 .../clang/Basic/DiagnosticSemaKinds.td|  4 ++
 clang/lib/Sema/SemaOverload.cpp   | 38 ++-
 clang/test/CXX/drs/dr28xx.cpp | 64 +++
 4 files changed, 106 insertions(+), 3 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a1390d6536b28c..7c8d83bd73613b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -164,6 +164,9 @@ Resolutions to C++ Defect Reports
 - Clang now diagnoses declarative nested-name-specifiers with 
pack-index-specifiers.
   (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers 
`_).
 
+- Allow floating-point promotions and conversions in converted constant 
expressions.
+  (`CWG2851 Allow floating-point conversions in converted constant expressions 
`_).
+
 C Language Changes
 --
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdca82934cb4dc..cb248f2ea6374b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -85,6 +85,10 @@ def err_expr_not_cce : Error<
   "%select{case value|enumerator value|non-type template argument|"
   "array size|explicit specifier argument|noexcept specifier argument|"
   "call to 'size()'|call to 'data()'}0 is not a constant expression">;
+def err_float_conv_cant_represent : Error<
+  "non-type template argument evaluates to %0 which cannot be "
+  "exactly represented in type %1"
+>;
 def ext_cce_narrowing : ExtWarn<
   "%select{case value|enumerator value|non-type template argument|"
   "array size|explicit specifier argument|noexcept specifier argument|"
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 04cd9e78739d20..40d65638e3afc1 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -6072,6 +6072,10 @@ static bool CheckConvertedConstantConversions(Sema ,
   case ICK_Integral_Promotion:
   case ICK_Integral_Conversion: // Narrowing conversions are checked elsewhere.
   case ICK_Zero_Queue_Conversion:
+  // Per CWG2851, floating-point promotions and conversions are allowed.
+  // The value of a conversion is checked afterwards.
+  case ICK_Floating_Promotion:
+  case ICK_Floating_Conversion:
 return true;
 
   case ICK_Boolean_Conversion:
@@ -6091,9 +6095,7 @@ static bool CheckConvertedConstantConversions(Sema ,
 // only permitted if the source type is std::nullptr_t.
 return SCS.getFromType()->isNullPtrType();
 
-  case ICK_Floating_Promotion:
   case ICK_Complex_Promotion:
-  case ICK_Floating_Conversion:
   case ICK_Complex_Conversion:
   case ICK_Floating_Integral:
   case ICK_Compatible_Conversion:
@@ -6229,7 +6231,37 @@ static ExprResult BuildConvertedConstantExpression(Sema 
, Expr *From,
   if (Result.isInvalid())
 return Result;
 
-  // Check for a narrowing implicit conversion.
+  if (SCS->Second == ICK_Floating_Conversion) {
+// Unlike with narrowing conversions, the value must fit
+// exactly even if it is in range
+assert(CCE == Sema::CCEKind::CCEK_TemplateArg &&
+   "Only non-type template args should use floating-point 
conversions");
+
+// Initializer is From, except it is a full-expression
+const Expr *Initializer =
+IgnoreNarrowingConversion(S.Context, Result.get());
+
+// If it's value-dependent, we can't tell whether it will fit
+if (Initializer->isValueDependent())
+  return Result;
+
+// Not-constant diagnosed afterwards
+if (!Initializer->isCXX11ConstantExpr(S.Context, ))
+  return Result;
+
+llvm::APFloat PostNarrowingValue = PreNarrowingValue.getFloat();
+bool LosesInfo = true;
+PostNarrowingValue.convert(S.Context.getFloatTypeSemantics(T),
+   llvm::APFloat::rmNearestTiesToEven, );
+
+if (LosesInfo)
+  S.Diag(From->getBeginLoc(), diag::err_float_conv_cant_represent)
+  << PreNarrowingValue.getAsString(S.Context, From->getType()) << T;
+
+return Result;
+  }
+
+  // Check for a narrowing integer conversion.
   bool ReturnPreNarrowingValue = false;
   QualType PreNarrowingType;
   switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue,
diff --git a/clang/test/CXX/drs/dr28xx.cpp b/clang/test/CXX/drs/dr28xx.cpp
index 4d9b0c76758d53..1626b1a9bf7b5b 100644
--- a/clang/test/CXX/drs/dr28xx.cpp
+++ b/clang/test/CXX/drs/dr28xx.cpp
@@ -3,6 +3,7 @@
 // RUN: 

[clang] [clang] Implement CWG2851: floating-point conversions in converted constant expressions (PR #90387)

2024-04-28 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/90387

>From a87399f8a41bb7d9a61c2d44c75836d86c6b4c38 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 28 Apr 2024 09:48:47 +0100
Subject: [PATCH] [clang] Implement CWG2851: floating-point conversions in
 converted constant expressions

---
 clang/docs/ReleaseNotes.rst   |  3 +
 .../clang/Basic/DiagnosticSemaKinds.td|  4 ++
 clang/lib/Sema/SemaOverload.cpp   | 37 ++-
 clang/test/CXX/drs/dr28xx.cpp | 64 +++
 4 files changed, 105 insertions(+), 3 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a1390d6536b28c..7c8d83bd73613b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -164,6 +164,9 @@ Resolutions to C++ Defect Reports
 - Clang now diagnoses declarative nested-name-specifiers with 
pack-index-specifiers.
   (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers 
`_).
 
+- Allow floating-point promotions and conversions in converted constant 
expressions.
+  (`CWG2851 Allow floating-point conversions in converted constant expressions 
`_).
+
 C Language Changes
 --
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdca82934cb4dc..cb248f2ea6374b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -85,6 +85,10 @@ def err_expr_not_cce : Error<
   "%select{case value|enumerator value|non-type template argument|"
   "array size|explicit specifier argument|noexcept specifier argument|"
   "call to 'size()'|call to 'data()'}0 is not a constant expression">;
+def err_float_conv_cant_represent : Error<
+  "non-type template argument evaluates to %0 which cannot be "
+  "exactly represented in type %1"
+>;
 def ext_cce_narrowing : ExtWarn<
   "%select{case value|enumerator value|non-type template argument|"
   "array size|explicit specifier argument|noexcept specifier argument|"
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 04cd9e78739d20..474a8a4b5654cb 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -6072,6 +6072,10 @@ static bool CheckConvertedConstantConversions(Sema ,
   case ICK_Integral_Promotion:
   case ICK_Integral_Conversion: // Narrowing conversions are checked elsewhere.
   case ICK_Zero_Queue_Conversion:
+  // Per CWG2851, floating-point promotions and conversions are allowed.
+  // The value of a conversion is checked afterwards.
+  case ICK_Floating_Promotion:
+  case ICK_Floating_Conversion:
 return true;
 
   case ICK_Boolean_Conversion:
@@ -6091,9 +6095,7 @@ static bool CheckConvertedConstantConversions(Sema ,
 // only permitted if the source type is std::nullptr_t.
 return SCS.getFromType()->isNullPtrType();
 
-  case ICK_Floating_Promotion:
   case ICK_Complex_Promotion:
-  case ICK_Floating_Conversion:
   case ICK_Complex_Conversion:
   case ICK_Floating_Integral:
   case ICK_Compatible_Conversion:
@@ -6229,7 +6231,36 @@ static ExprResult BuildConvertedConstantExpression(Sema 
, Expr *From,
   if (Result.isInvalid())
 return Result;
 
-  // Check for a narrowing implicit conversion.
+  if (SCS->Second == ICK_Floating_Conversion) {
+// Unlike with narrowing conversions, the value must fit
+// exactly even if it is in range
+assert(CCE == Sema::CCEKind::CCEK_TemplateArg &&
+   "Only non-type template args should use floating-point 
conversions");
+
+// Initializer is From, except it is a full-expression
+const Expr *Initializer =
+IgnoreNarrowingConversion(S.Context, Result.get());
+
+// If it's value-dependent, we can't tell whether it will fit
+if (Initializer->isValueDependent())
+  return Result;
+
+// Not-constant diagnosed afterwards
+if (!Initializer->isCXX11ConstantExpr(S.Context, ))
+  return Result;
+
+llvm::APFloat PostNarrowingValue = PreNarrowingValue.getFloat();
+bool LosesInfo = true;
+PostNarrowingValue.convert(S.Context.getFloatTypeSemantics(T), 
llvm::APFloat::rmNearestTiesToEven, );
+
+if (LosesInfo)
+  S.Diag(From->getBeginLoc(), diag::err_float_conv_cant_represent)
+  << PreNarrowingValue.getAsString(S.Context, From->getType()) << T;
+
+return Result;
+  }
+
+  // Check for a narrowing integer conversion.
   bool ReturnPreNarrowingValue = false;
   QualType PreNarrowingType;
   switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue,
diff --git a/clang/test/CXX/drs/dr28xx.cpp b/clang/test/CXX/drs/dr28xx.cpp
index 4d9b0c76758d53..1626b1a9bf7b5b 100644
--- a/clang/test/CXX/drs/dr28xx.cpp
+++ b/clang/test/CXX/drs/dr28xx.cpp
@@ -3,6 +3,7 @@
 // RUN: %clang_cc1 -std=c++14 

[clang] [clang] Implement CWG2851: floating-point conversions in converted constant expressions (PR #90387)

2024-04-28 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok created 
https://github.com/llvm/llvm-project/pull/90387

https://cplusplus.github.io/CWG/issues/2851.html

The only time the target type for a converted constant expression is a 
floating-point type is in a NTTP, so this only affects C++20+.

>From 3d56657f03ab6824bf6717a89b4b2f757770aad5 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 28 Apr 2024 09:48:47 +0100
Subject: [PATCH] [clang] Implement CWG2851: floating-point conversions in
 converted constant expressions

---
 clang/docs/ReleaseNotes.rst   |  3 ++
 .../clang/Basic/DiagnosticSemaKinds.td|  4 ++
 clang/lib/Sema/SemaOverload.cpp   | 38 +--
 clang/test/CXX/drs/dr28xx.cpp | 35 +
 4 files changed, 77 insertions(+), 3 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a1390d6536b28c..7c8d83bd73613b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -164,6 +164,9 @@ Resolutions to C++ Defect Reports
 - Clang now diagnoses declarative nested-name-specifiers with 
pack-index-specifiers.
   (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers 
`_).
 
+- Allow floating-point promotions and conversions in converted constant 
expressions.
+  (`CWG2851 Allow floating-point conversions in converted constant expressions 
`_).
+
 C Language Changes
 --
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdca82934cb4dc..08ebb28ff17b25 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -85,6 +85,10 @@ def err_expr_not_cce : Error<
   "%select{case value|enumerator value|non-type template argument|"
   "array size|explicit specifier argument|noexcept specifier argument|"
   "call to 'size()'|call to 'data()'}0 is not a constant expression">;
+def err_float_conv_cant_represent : Error<
+  "non-type template argument evaluates to %0 which can not be "
+  "represented in type %1"
+>;
 def ext_cce_narrowing : ExtWarn<
   "%select{case value|enumerator value|non-type template argument|"
   "array size|explicit specifier argument|noexcept specifier argument|"
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 04cd9e78739d20..c35517db946b1c 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -6072,6 +6072,10 @@ static bool CheckConvertedConstantConversions(Sema ,
   case ICK_Integral_Promotion:
   case ICK_Integral_Conversion: // Narrowing conversions are checked elsewhere.
   case ICK_Zero_Queue_Conversion:
+  // Per CWG2851, floating-point promotions and conversions are allowed.
+  // The value of a conversion is checked afterwards.
+  case ICK_Floating_Promotion:
+  case ICK_Floating_Conversion:
 return true;
 
   case ICK_Boolean_Conversion:
@@ -6091,9 +6095,7 @@ static bool CheckConvertedConstantConversions(Sema ,
 // only permitted if the source type is std::nullptr_t.
 return SCS.getFromType()->isNullPtrType();
 
-  case ICK_Floating_Promotion:
   case ICK_Complex_Promotion:
-  case ICK_Floating_Conversion:
   case ICK_Complex_Conversion:
   case ICK_Floating_Integral:
   case ICK_Compatible_Conversion:
@@ -6229,7 +6231,37 @@ static ExprResult BuildConvertedConstantExpression(Sema 
, Expr *From,
   if (Result.isInvalid())
 return Result;
 
-  // Check for a narrowing implicit conversion.
+  if (SCS->Second == ICK_Floating_Conversion) {
+// Unlike with narrowing conversions, the value must fit
+// exactly even if it is in range
+assert(CCE == Sema::CCEKind::CCEK_TemplateArg &&
+   "Only non-type template args should use floating-point 
conversions");
+
+// Initializer is From, except it is a full-expression
+const Expr *Initializer =
+IgnoreNarrowingConversion(S.Context, Result.get());
+
+// If it's value-dependent, we can't tell whether it will fit
+if (Initializer->isValueDependent())
+  return Result;
+
+if (!Initializer->isCXX11ConstantExpr(S.Context, )) {
+  S.Diag(Initializer->getBeginLoc(), diag::err_expr_not_cce) << CCE;
+  return Result;
+}
+
+llvm::APFloat PostNarrowingValue = PreNarrowingValue.getFloat();
+bool LosesInfo = true;
+PostNarrowingValue.convert(S.Context.getFloatTypeSemantics(T),
+   llvm::APFloat::rmNearestTiesToEven, );
+if (LosesInfo)
+  S.Diag(From->getBeginLoc(), diag::err_float_conv_cant_represent)
+  << PreNarrowingValue.getAsString(S.Context, From->getType()) << T;
+
+return Result;
+  }
+
+  // Check for a narrowing integer conversion.
   bool ReturnPreNarrowingValue = false;
   QualType PreNarrowingType;
   switch (SCS->getNarrowingKind(S.Context, Result.get(), 

[clang] [SemaCXX] Qualified functions can't decay into pointers (PR #90353)

2024-04-27 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok created 
https://github.com/llvm/llvm-project/pull/90353

Fixes #27059

Dependent function parameters, template parameters and exception declarations 
that have qualified function types now error instead of silently decaying into 
an invalid pointer type.

Also fix __decay and __add_pointer for these types which previously just 
ignored the qualifiers

>From 9319c295d96550dfd703559f7c7fc980a68fb286 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sat, 27 Apr 2024 19:15:00 +0100
Subject: [PATCH] [SemaCXX] Qualified functions can't decay into pointers

Fixes #27059

Dependent function parameters, template parameters and exception
declarations that have qualified function types now error instead of
silently decaying into an invalid pointer type.

Also fix __decay and __add_pointer for these types which previously
just ignored the qualifiers
---
 clang/include/clang/AST/Type.h|  4 +-
 clang/lib/AST/TypePrinter.cpp | 23 ++
 clang/lib/Sema/SemaDecl.cpp   |  7 +++
 clang/lib/Sema/SemaDeclCXX.cpp| 16 +--
 clang/lib/Sema/SemaTemplate.cpp   | 24 +-
 clang/lib/Sema/SemaType.cpp   | 46 +++
 .../dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp|  5 +-
 .../CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp   |  5 +-
 clang/test/SemaCXX/function-type-qual.cpp | 36 ++-
 clang/test/SemaCXX/type-traits.cpp| 12 +
 10 files changed, 135 insertions(+), 43 deletions(-)

diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index dff02d4861b3db..bf8187385f062c 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -5035,6 +5035,8 @@ class FunctionProtoType final
 return static_cast(FunctionTypeBits.RefQualifier);
   }
 
+  std::string getFunctionQualifiersAsString() const;
+
   using param_type_iterator = const QualType *;
 
   ArrayRef param_types() const {
@@ -7370,7 +7372,7 @@ inline bool QualType::isReferenceable() const {
   if (const auto *F = Self.getAs())
 return F->getMethodQuals().empty() && F->getRefQualifier() == RQ_None;
 
-  return false;
+  return Self.isFunctionType();
 }
 
 inline SplitQualType QualType::split() const {
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 9602f448e94279..720ac254539f11 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2571,3 +2571,26 @@ raw_ostream ::operator<<(raw_ostream , QualType 
QT) {
   TypePrinter(LangOptions()).print(S.Ty, S.Quals, OS, /*PlaceHolder=*/"");
   return OS;
 }
+
+std::string FunctionProtoType::getFunctionQualifiersAsString() const {
+  std::string Quals = getMethodQuals().getAsString();
+
+  switch (getRefQualifier()) {
+  case RQ_None:
+break;
+
+  case RQ_LValue:
+if (!Quals.empty())
+  Quals += ' ';
+Quals += '&';
+break;
+
+  case RQ_RValue:
+if (!Quals.empty())
+  Quals += ' ';
+Quals += "&&";
+break;
+  }
+
+  return Quals;
+}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index e0745fe9a45367..66748fd9ca17f6 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15392,6 +15392,13 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, 
SourceLocation StartLoc,
 T = Context.getLifetimeQualifiedType(T, lifetime);
   }
 
+  if (T->isFunctionType() && !T.isReferenceable()) {
+Diag(NameLoc, diag::err_compound_qualified_function_type)
+<< 1 << true << T
+<< T->castAs()->getFunctionQualifiersAsString();
+return nullptr;
+  }
+
   ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name,
  Context.getAdjustedParameterType(T),
  TSInfo, SC, nullptr);
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index abdbc9d8830c03..d5630b609cabc4 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -11323,7 +11323,8 @@ void Sema::CheckConversionDeclarator(Declarator , 
QualType ,
 D.setInvalidType();
   } else if (ConvType->isFunctionType()) {
 Diag(D.getIdentifierLoc(), diag::err_conv_function_to_function);
-ConvType = Context.getPointerType(ConvType);
+if (ConvType.isReferenceable())
+  ConvType = Context.getPointerType(ConvType);
 D.setInvalidType();
   }
 
@@ -16974,8 +16975,17 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, 
TypeSourceInfo *TInfo,
   // Arrays and functions decay.
   if (ExDeclType->isArrayType())
 ExDeclType = Context.getArrayDecayedType(ExDeclType);
-  else if (ExDeclType->isFunctionType())
-ExDeclType = Context.getPointerType(ExDeclType);
+  else if (ExDeclType->isFunctionType()) {
+if (ExDeclType.isReferenceable())
+  ExDeclType = Context.getPointerType(ExDeclType);
+else {
+  Diag(Loc, diag::err_compound_qualified_function_type)
+

[clang] [clang] [SemaCXX] Implement CWG2627 Bit-fields and narrowing conversions (PR #78112)

2024-04-26 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

New version gives a pedantic warning if this is used before C++23 (and it is a 
substitution failure before C++23)

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


[clang] [clang] [SemaCXX] Implement CWG2627 Bit-fields and narrowing conversions (PR #78112)

2024-04-26 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/78112

>From 92f8720e3d21521b589d5291f086a2f32b87bfe0 Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sun, 14 Jan 2024 19:52:31 +
Subject: [PATCH] [clang] [SemaCXX] Implement CWG2627 Bit-fields and narrowing
 conversions

---
 clang/docs/ReleaseNotes.rst   |   5 +
 .../clang/Basic/DiagnosticSemaKinds.td|   3 +
 clang/include/clang/Sema/Overload.h   |   7 +-
 clang/lib/Sema/SemaExpr.cpp   |  10 +-
 clang/lib/Sema/SemaInit.cpp   |  20 ++-
 clang/lib/Sema/SemaOverload.cpp   | 119 +--
 .../dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp |  24 
 clang/test/CXX/drs/dr26xx.cpp | 136 ++
 clang/www/cxx_dr_status.html  |   2 +-
 9 files changed, 278 insertions(+), 48 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92563262cc6737..28202fc604e298 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -157,6 +157,11 @@ Resolutions to C++ Defect Reports
 - Clang now diagnoses declarative nested-name-specifiers with 
pack-index-specifiers.
   (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers 
`_).
 
+- Casts from a bit-field to an integral type is now not considered narrowing 
if the
+  width of the bit-field means that all potential values are in the range
+  of the target type, even if the type of the bit-field is larger.
+  (`CWG2627. Bit-fields and narrowing conversions  
`_).
+
 C Language Changes
 --
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdca82934cb4dc..6cdb439be30ae5 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6253,6 +6253,9 @@ def ext_init_list_variable_narrowing_const_reference : 
ExtWarn<
 def ext_init_list_constant_narrowing : ExtWarn<
   "constant expression evaluates to %0 which cannot be narrowed to type %1">,
   InGroup, DefaultError, SFINAEFailure;
+def ext_bit_field_narrowing : Extension<
+  "narrowing non-constant-expression from %0 bit-field of width %2 to %1 is a 
C++23 extension">,
+  InGroup, SFINAEFailure;
 def ext_init_list_constant_narrowing_const_reference : ExtWarn<
   ext_init_list_constant_narrowing.Summary>,
   InGroup, DefaultError, SFINAEFailure;
diff --git a/clang/include/clang/Sema/Overload.h 
b/clang/include/clang/Sema/Overload.h
index 76311b00d2fc58..0d94045cc13f79 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -244,7 +244,11 @@ class Sema;
 /// Not a narrowing conversion.
 NK_Not_Narrowing,
 
-/// A narrowing conversion by virtue of the source and destination types.
+/// Not a narrowing conversion in C++23 because the source is a bit-field
+/// whose range can fit in the target type
+NK_BitField_Not_Narrowing,
+
+/// A narrowing conversion by virtue of the source and target types.
 NK_Type_Narrowing,
 
 /// A narrowing conversion, because a constant expression got narrowed.
@@ -387,6 +391,7 @@ class Sema;
 NarrowingKind
 getNarrowingKind(ASTContext , const Expr *Converted,
  APValue , QualType ,
+ unsigned ,
  bool IgnoreFloatToIntegralConversion = false) const;
 bool isPointerConversionToBool() const;
 bool isPointerConversionToVoidPointer(ASTContext& Context) const;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 50f92c496a539a..4c16fcc60fc771 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -12361,8 +12361,9 @@ static bool checkThreeWayNarrowingConversion(Sema , 
QualType ToType, Expr *E,
 
   APValue PreNarrowingValue;
   QualType PreNarrowingType;
+  unsigned BitFieldWidth;
   switch (SCS.getNarrowingKind(S.Context, E, PreNarrowingValue,
-   PreNarrowingType,
+   PreNarrowingType, BitFieldWidth,
/*IgnoreFloatToIntegralConversion*/ true)) {
   case NK_Dependent_Narrowing:
 // Implicit conversion to a narrower type, but the expression is
@@ -12370,6 +12371,13 @@ static bool checkThreeWayNarrowingConversion(Sema , 
QualType ToType, Expr *E,
   case NK_Not_Narrowing:
 return false;
 
+  case NK_BitField_Not_Narrowing:
+if (!S.getLangOpts().CPlusPlus23) {
+  return S.Diag(E->getBeginLoc(), diag::ext_bit_field_narrowing)
+ << FromType << ToType << BitFieldWidth;
+}
+return false;
+
   case NK_Constant_Narrowing:
 // Implicit conversion to a narrower type, and the value is not a constant
 // expression.
diff --git a/clang/lib/Sema/SemaInit.cpp 

[clang] [SemaCXX] Implement CWG2351 `void{}` (PR #78060)

2024-04-26 Thread Mital Ashok via cfe-commits

https://github.com/MitalAshok updated 
https://github.com/llvm/llvm-project/pull/78060

>From 6ed7cad5d4993603221c3d9a777463675d69643b Mon Sep 17 00:00:00 2001
From: Mital Ashok 
Date: Sat, 13 Jan 2024 18:03:15 +
Subject: [PATCH] [SemaCXX] Implement CWG2351 `void{}`

---
 clang/docs/ReleaseNotes.rst|  3 ++
 clang/include/clang/AST/ExprCXX.h  |  5 +--
 clang/lib/Sema/SemaExprCXX.cpp | 23 
 clang/lib/Sema/SemaInit.cpp|  1 +
 clang/test/CXX/drs/dr23xx.cpp  | 41 +-
 clang/test/SemaCXX/attr-annotate.cpp   |  4 +--
 clang/test/SemaCXX/cxx2a-explicit-bool.cpp |  4 +--
 clang/test/SemaCXX/sugared-auto.cpp|  6 
 clang/www/cxx_dr_status.html   |  2 +-
 9 files changed, 75 insertions(+), 14 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92563262cc6737..28cd1a8abd4c65 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -157,6 +157,9 @@ Resolutions to C++ Defect Reports
 - Clang now diagnoses declarative nested-name-specifiers with 
pack-index-specifiers.
   (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers 
`_).
 
+- Implemented `CWG2351 `_ which allows ``void{}``
+  as a prvalue of type ``void``.
+
 C Language Changes
 --
 
diff --git a/clang/include/clang/AST/ExprCXX.h 
b/clang/include/clang/AST/ExprCXX.h
index a915745d2d7322..8fa5c0c79f6a02 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -2170,8 +2170,9 @@ class LambdaExpr final : public Expr,
   const_child_range children() const;
 };
 
-/// An expression "T()" which creates a value-initialized rvalue of type
-/// T, which is a non-class type.  See (C++98 [5.2.3p2]).
+/// An expression "T()" which creates an rvalue of a non-class type T.
+/// For non-void T, the rvalue is value-initialized.
+/// See (C++98 [5.2.3p2]).
 class CXXScalarValueInitExpr : public Expr {
   friend class ASTStmtReader;
 
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 779a41620033dc..269aedb59ca8f1 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1660,12 +1660,23 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
 return ExprError(Diag(TyBeginLoc, diag::err_init_for_function_type)
<< Ty << FullRange);
 
-  // C++17 [expr.type.conv]p2:
-  //   If the type is cv void and the initializer is (), the expression is a
-  //   prvalue of the specified type that performs no initialization.
-  if (!Ty->isVoidType() &&
-  RequireCompleteType(TyBeginLoc, ElemTy,
-  diag::err_invalid_incomplete_type_use, FullRange))
+  // C++17 [expr.type.conv]p2, per DR2351:
+  //   If the type is cv void and the initializer is () or {}, the expression 
is
+  //   a prvalue of the specified type that performs no initialization.
+  if (Ty->isVoidType()) {
+if (Exprs.empty())
+  return new (Context) CXXScalarValueInitExpr(
+  Ty.getUnqualifiedType(), TInfo, Kind.getRange().getEnd());
+if (ListInitialization &&
+cast(Exprs[0])->getNumInits() == 0) {
+  return CXXFunctionalCastExpr::Create(
+  Context, Ty.getUnqualifiedType(), VK_PRValue, TInfo, CK_NoOp,
+  Exprs[0], /*Path=*/nullptr, CurFPFeatureOverrides(),
+  Exprs[0]->getBeginLoc(), Exprs[0]->getEndLoc());
+}
+  } else if (RequireCompleteType(TyBeginLoc, ElemTy,
+ diag::err_invalid_incomplete_type_use,
+ FullRange))
 return ExprError();
 
   //   Otherwise, the expression is a prvalue of the specified type whose
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 003a157990d307..3bb8407c893d9d 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5344,6 +5344,7 @@ static void TryValueInitialization(Sema ,
   //
   //   To value-initialize an object of type T means:
   QualType T = Entity.getType();
+  assert(!T->isVoidType() && "Cannot value-init void");
 
   // -- if T is an array type, then each element is value-initialized;
   T = S.Context.getBaseElementType(T);
diff --git a/clang/test/CXX/drs/dr23xx.cpp b/clang/test/CXX/drs/dr23xx.cpp
index db5b7c3cd3c9a2..cd21af0daf3d0f 100644
--- a/clang/test/CXX/drs/dr23xx.cpp
+++ b/clang/test/CXX/drs/dr23xx.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++98 %s -verify=expected -fexceptions 
-fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -std=c++98 %s -verify=expected,cxx98-03 -fexceptions 
-fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -std=c++03 %s -verify=expected,cxx98-03 -fexceptions 
-fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
 // RUN: %clang_cc1 -std=c++11 %s -verify=expected,since-cxx11 

[clang] [SemaCXX] Implement CWG2351 `void{}` (PR #78060)

2024-04-26 Thread Mital Ashok via cfe-commits


@@ -1600,12 +1600,25 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
 return ExprError(Diag(TyBeginLoc, diag::err_init_for_function_type)
<< Ty << FullRange);
 
-  // C++17 [expr.type.conv]p2:
-  //   If the type is cv void and the initializer is (), the expression is a
-  //   prvalue of the specified type that performs no initialization.
-  if (!Ty->isVoidType() &&
-  RequireCompleteType(TyBeginLoc, ElemTy,
-  diag::err_invalid_incomplete_type_use, FullRange))
+  // C++17 [expr.type.conv]p2, per DR2351:
+  //   If the type is cv void and the initializer is () or {}, the expression 
is
+  //   a prvalue of the specified type that performs no initialization.
+  if (Ty->isVoidType()) {

MitalAshok wrote:

[[expr.type.conv]p2](https://wg21.link/expr.type.conv#2) reads 
"`T(expression-list)` or `T braced-init-list` is a cast expression, a prvalue 
`void`, or direct-initialized from the initializer". So when we encounter 
`void()` or `void{}`, we shouldn't actually use initialization semantics.

Previously, `void()` worked because 
https://github.com/llvm/llvm-project/blob/2d09ac4037415ab0044ad508aae2ff8b2559a9d8/clang/lib/Sema/SemaInit.cpp#L6255-L6260
 made it a value initialization by accident, and we allowed value initializing 
void

I've now added an assertion for `void` in `TryValueInitialization` because you 
shouldn't actually be able to get there, since there's no standard way to call 
for the value-intialization of `void`

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


[clang] [SemaCXX] Recognise initializer_list injected-class-name types as initializer_lists (PR #90210)

2024-04-26 Thread Mital Ashok via cfe-commits

MitalAshok wrote:

Original Differential revision: https://reviews.llvm.org/D156064

Doesn't appear that anything has changed since, just rebased the changes.

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


  1   2   >