Skip to content

Commit 7ab2a18

Browse files
SC llvm teamSC llvm team
SC llvm team
authored and
SC llvm team
committed
Merged main:73185854a3fc469b7d3e21d0b5d2ecb5ee15d201 into amd-gfx:e849a3027d34
Local branch amd-gfx e849a30 Merged main:6d160a49c2e7f36367de3f61f0460e28921450d5 into amd-gfx:71200611d382 Remote branch main 7318585 [clang] Implement CWG1719 "Layout compatibility and cv-qualification revisited" (llvm#82358)
2 parents e849a30 + 7318585 commit 7ab2a18

File tree

74 files changed

+12343
-10948
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+12343
-10948
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,8 @@ C++20 Feature Support
9898

9999
- Implemented the `__is_layout_compatible` intrinsic to support
100100
`P0466R5: Layout-compatibility and Pointer-interconvertibility Traits <https://wg21.link/P0466R5>`_.
101-
Note: `CWG1719: Layout compatibility and cv-qualification revisited <https://cplusplus.github.io/CWG/issues/1719.html>`_
102-
and `CWG2759: [[no_unique_address] and common initial sequence <https://cplusplus.github.io/CWG/issues/2759.html>`_
103-
are not yet implemented.
101+
Note: `CWG2759: [[no_unique_address] and common initial sequence <https://cplusplus.github.io/CWG/issues/2759.html>`_
102+
is not yet implemented.
104103

105104
C++23 Feature Support
106105
^^^^^^^^^^^^^^^^^^^^^
@@ -120,6 +119,10 @@ Resolutions to C++ Defect Reports
120119
in the template parameters, but is deduced from a previous argument.
121120
(`#78449: <https://github.com/llvm/llvm-project/issues/78449>`_).
122121

122+
- Type qualifications are now ignored when evaluating layout compatibility
123+
of two types.
124+
(`CWG1719: Layout compatibility and cv-qualification revisited <https://cplusplus.github.io/CWG/issues/1719.html>`_).
125+
123126
C Language Changes
124127
------------------
125128

@@ -279,6 +282,8 @@ Bug Fixes to C++ Support
279282
Fixes (`#68490 <https://github.com/llvm/llvm-project/issues/68490>`_)
280283
- Fix a crash when trying to call a varargs function that also has an explicit object parameter.
281284
Fixes (`#80971 ICE when explicit object parameter be a function parameter pack`)
285+
- Reject explicit object parameters on `new` and `delete` operators.
286+
Fixes (`#82249 <https://github.com/llvm/llvm-project/issues/82249>` _)
282287
- Fixed a bug where abbreviated function templates would append their invented template parameters to
283288
an empty template parameter lists.
284289
- Clang now classifies aggregate initialization in C++17 and newer as constant

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 12 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,15 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
8181
if (DiscardResult)
8282
return this->discard(SubExpr);
8383

84-
return dereference(
85-
SubExpr, DerefKind::Read,
86-
[](PrimType) {
87-
// Value loaded - nothing to do here.
88-
return true;
89-
},
90-
[this, CE](PrimType T) {
91-
// Pointer on stack - dereference it.
92-
return this->emitLoadPop(T, CE);
93-
});
84+
if (SubExpr->getType()->isAnyComplexType())
85+
return this->delegate(SubExpr);
86+
87+
if (!this->visit(SubExpr))
88+
return false;
89+
90+
if (std::optional<PrimType> SubExprT = classify(SubExpr->getType()))
91+
return this->emitLoadPop(*SubExprT, CE);
92+
return false;
9493
}
9594

9695
case CK_UncheckedDerivedToBase:
@@ -2326,134 +2325,6 @@ bool ByteCodeExprGen<Emitter>::visitZeroRecordInitializer(const Record *R,
23262325
return true;
23272326
}
23282327

2329-
template <class Emitter>
2330-
bool ByteCodeExprGen<Emitter>::dereference(
2331-
const Expr *LV, DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
2332-
llvm::function_ref<bool(PrimType)> Indirect) {
2333-
if (std::optional<PrimType> T = classify(LV->getType())) {
2334-
if (!LV->refersToBitField()) {
2335-
// Only primitive, non bit-field types can be dereferenced directly.
2336-
if (const auto *DE = dyn_cast<DeclRefExpr>(LV)) {
2337-
if (!DE->getDecl()->getType()->isReferenceType()) {
2338-
if (const auto *PD = dyn_cast<ParmVarDecl>(DE->getDecl()))
2339-
return dereferenceParam(LV, *T, PD, AK, Direct, Indirect);
2340-
if (const auto *VD = dyn_cast<VarDecl>(DE->getDecl()))
2341-
return dereferenceVar(LV, *T, VD, AK, Direct, Indirect);
2342-
}
2343-
}
2344-
}
2345-
2346-
if (!visit(LV))
2347-
return false;
2348-
return Indirect(*T);
2349-
}
2350-
2351-
if (LV->getType()->isAnyComplexType())
2352-
return this->delegate(LV);
2353-
2354-
return false;
2355-
}
2356-
2357-
template <class Emitter>
2358-
bool ByteCodeExprGen<Emitter>::dereferenceParam(
2359-
const Expr *LV, PrimType T, const ParmVarDecl *PD, DerefKind AK,
2360-
llvm::function_ref<bool(PrimType)> Direct,
2361-
llvm::function_ref<bool(PrimType)> Indirect) {
2362-
if (auto It = this->Params.find(PD); It != this->Params.end()) {
2363-
unsigned Idx = It->second.Offset;
2364-
switch (AK) {
2365-
case DerefKind::Read:
2366-
return DiscardResult ? true : this->emitGetParam(T, Idx, LV);
2367-
2368-
case DerefKind::Write:
2369-
if (!Direct(T))
2370-
return false;
2371-
if (!this->emitSetParam(T, Idx, LV))
2372-
return false;
2373-
return DiscardResult ? true : this->emitGetPtrParam(Idx, LV);
2374-
2375-
case DerefKind::ReadWrite:
2376-
if (!this->emitGetParam(T, Idx, LV))
2377-
return false;
2378-
if (!Direct(T))
2379-
return false;
2380-
if (!this->emitSetParam(T, Idx, LV))
2381-
return false;
2382-
return DiscardResult ? true : this->emitGetPtrParam(Idx, LV);
2383-
}
2384-
return true;
2385-
}
2386-
2387-
// If the param is a pointer, we can dereference a dummy value.
2388-
if (!DiscardResult && T == PT_Ptr && AK == DerefKind::Read) {
2389-
if (auto Idx = P.getOrCreateDummy(PD))
2390-
return this->emitGetPtrGlobal(*Idx, PD);
2391-
return false;
2392-
}
2393-
2394-
// Value cannot be produced - try to emit pointer and do stuff with it.
2395-
return visit(LV) && Indirect(T);
2396-
}
2397-
2398-
template <class Emitter>
2399-
bool ByteCodeExprGen<Emitter>::dereferenceVar(
2400-
const Expr *LV, PrimType T, const VarDecl *VD, DerefKind AK,
2401-
llvm::function_ref<bool(PrimType)> Direct,
2402-
llvm::function_ref<bool(PrimType)> Indirect) {
2403-
auto It = Locals.find(VD);
2404-
if (It != Locals.end()) {
2405-
const auto &L = It->second;
2406-
switch (AK) {
2407-
case DerefKind::Read:
2408-
if (!this->emitGetLocal(T, L.Offset, LV))
2409-
return false;
2410-
return DiscardResult ? this->emitPop(T, LV) : true;
2411-
2412-
case DerefKind::Write:
2413-
if (!Direct(T))
2414-
return false;
2415-
if (!this->emitSetLocal(T, L.Offset, LV))
2416-
return false;
2417-
return DiscardResult ? true : this->emitGetPtrLocal(L.Offset, LV);
2418-
2419-
case DerefKind::ReadWrite:
2420-
if (!this->emitGetLocal(T, L.Offset, LV))
2421-
return false;
2422-
if (!Direct(T))
2423-
return false;
2424-
if (!this->emitSetLocal(T, L.Offset, LV))
2425-
return false;
2426-
return DiscardResult ? true : this->emitGetPtrLocal(L.Offset, LV);
2427-
}
2428-
} else if (auto Idx = P.getGlobal(VD)) {
2429-
switch (AK) {
2430-
case DerefKind::Read:
2431-
if (!this->emitGetGlobal(T, *Idx, LV))
2432-
return false;
2433-
return DiscardResult ? this->emitPop(T, LV) : true;
2434-
2435-
case DerefKind::Write:
2436-
if (!Direct(T))
2437-
return false;
2438-
if (!this->emitSetGlobal(T, *Idx, LV))
2439-
return false;
2440-
return DiscardResult ? true : this->emitGetPtrGlobal(*Idx, LV);
2441-
2442-
case DerefKind::ReadWrite:
2443-
if (!this->emitGetGlobal(T, *Idx, LV))
2444-
return false;
2445-
if (!Direct(T))
2446-
return false;
2447-
if (!this->emitSetGlobal(T, *Idx, LV))
2448-
return false;
2449-
return DiscardResult ? true : this->emitGetPtrGlobal(*Idx, LV);
2450-
}
2451-
}
2452-
2453-
// Value cannot be produced - try to emit pointer.
2454-
return visit(LV) && Indirect(T);
2455-
}
2456-
24572328
template <class Emitter>
24582329
template <typename T>
24592330
bool ByteCodeExprGen<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) {
@@ -3092,15 +2963,9 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
30922963
// We should already have a pointer when we get here.
30932964
return this->delegate(SubExpr);
30942965
case UO_Deref: // *x
3095-
return dereference(
3096-
SubExpr, DerefKind::Read,
3097-
[](PrimType) {
3098-
llvm_unreachable("Dereferencing requires a pointer");
3099-
return false;
3100-
},
3101-
[this, E](PrimType T) {
3102-
return DiscardResult ? this->emitPop(T, E) : true;
3103-
});
2966+
if (DiscardResult)
2967+
return this->discard(SubExpr);
2968+
return this->visit(SubExpr);
31042969
case UO_Not: // ~x
31052970
if (!this->visit(SubExpr))
31062971
return false;

clang/lib/AST/Interp/ByteCodeExprGen.h

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -236,29 +236,6 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
236236
bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);
237237
bool visitZeroRecordInitializer(const Record *R, const Expr *E);
238238

239-
enum class DerefKind {
240-
/// Value is read and pushed to stack.
241-
Read,
242-
/// Direct method generates a value which is written. Returns pointer.
243-
Write,
244-
/// Direct method receives the value, pushes mutated value. Returns pointer.
245-
ReadWrite,
246-
};
247-
248-
/// Method to directly load a value. If the value can be fetched directly,
249-
/// the direct handler is called. Otherwise, a pointer is left on the stack
250-
/// and the indirect handler is expected to operate on that.
251-
bool dereference(const Expr *LV, DerefKind AK,
252-
llvm::function_ref<bool(PrimType)> Direct,
253-
llvm::function_ref<bool(PrimType)> Indirect);
254-
bool dereferenceParam(const Expr *LV, PrimType T, const ParmVarDecl *PD,
255-
DerefKind AK,
256-
llvm::function_ref<bool(PrimType)> Direct,
257-
llvm::function_ref<bool(PrimType)> Indirect);
258-
bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD,
259-
DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
260-
llvm::function_ref<bool(PrimType)> Indirect);
261-
262239
/// Emits an APSInt constant.
263240
bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E);
264241
bool emitConst(const llvm::APSInt &Value, const Expr *E);

clang/lib/AST/Interp/EvalEmitter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ EvaluationResult EvalEmitter::interpretExpr(const Expr *E,
4747
EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD,
4848
bool CheckFullyInitialized) {
4949
this->CheckFullyInitialized = CheckFullyInitialized;
50+
this->ConvertResultToRValue =
51+
VD->getAnyInitializer() &&
52+
(VD->getAnyInitializer()->getType()->isAnyComplexType());
5053
EvalResult.setSource(VD);
5154

5255
if (!this->visitDecl(VD) && EvalResult.empty())

clang/lib/AST/Interp/Interp.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -362,13 +362,13 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
362362
if (Ptr.isInitialized())
363363
return true;
364364

365+
if (const auto *VD = Ptr.getDeclDesc()->asVarDecl();
366+
VD && VD->hasGlobalStorage()) {
367+
const SourceInfo &Loc = S.Current->getSource(OpPC);
368+
S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
369+
S.Note(VD->getLocation(), diag::note_declared_at);
370+
}
365371
if (!S.checkingPotentialConstantExpression()) {
366-
if (const auto *VD = Ptr.getDeclDesc()->asVarDecl();
367-
VD && VD->hasGlobalStorage()) {
368-
const SourceInfo &Loc = S.Current->getSource(OpPC);
369-
S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
370-
S.Note(VD->getLocation(), diag::note_declared_at);
371-
}
372372
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
373373
<< AK << /*uninitialized=*/true << S.Current->getRange(OpPC);
374374
}

clang/lib/AST/Interp/Opcodes.td

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def FnPtr : Type;
3535
// Types transferred to the interpreter.
3636
//===----------------------------------------------------------------------===//
3737

38-
class ArgType { string Name = ?; }
38+
class ArgType { string Name = ?; bit AsRef = false; }
3939
def ArgSint8 : ArgType { let Name = "int8_t"; }
4040
def ArgUint8 : ArgType { let Name = "uint8_t"; }
4141
def ArgSint16 : ArgType { let Name = "int16_t"; }
@@ -44,9 +44,9 @@ def ArgSint32 : ArgType { let Name = "int32_t"; }
4444
def ArgUint32 : ArgType { let Name = "uint32_t"; }
4545
def ArgSint64 : ArgType { let Name = "int64_t"; }
4646
def ArgUint64 : ArgType { let Name = "uint64_t"; }
47-
def ArgFloat : ArgType { let Name = "Floating"; }
48-
def ArgIntAP : ArgType { let Name = "IntegralAP<false>"; }
49-
def ArgIntAPS : ArgType { let Name = "IntegralAP<true>"; }
47+
def ArgIntAP : ArgType { let Name = "IntegralAP<false>"; let AsRef = true; }
48+
def ArgIntAPS : ArgType { let Name = "IntegralAP<true>"; let AsRef = true; }
49+
def ArgFloat : ArgType { let Name = "Floating"; let AsRef = true; }
5050
def ArgBool : ArgType { let Name = "bool"; }
5151

5252
def ArgFunction : ArgType { let Name = "const Function *"; }

clang/lib/Sema/SemaChecking.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19124,15 +19124,16 @@ static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) {
1912419124
if (T1.isNull() || T2.isNull())
1912519125
return false;
1912619126

19127-
// C++11 [basic.types] p11:
19128-
// If two types T1 and T2 are the same type, then T1 and T2 are
19129-
// layout-compatible types.
19130-
if (C.hasSameType(T1, T2))
19131-
return true;
19132-
19127+
// C++20 [basic.types] p11:
19128+
// Two types cv1 T1 and cv2 T2 are layout-compatible types
19129+
// if T1 and T2 are the same type, layout-compatible enumerations (9.7.1),
19130+
// or layout-compatible standard-layout class types (11.4).
1913319131
T1 = T1.getCanonicalType().getUnqualifiedType();
1913419132
T2 = T2.getCanonicalType().getUnqualifiedType();
1913519133

19134+
if (C.hasSameType(T1, T2))
19135+
return true;
19136+
1913619137
const Type::TypeClass TC1 = T1->getTypeClass();
1913719138
const Type::TypeClass TC2 = T2->getTypeClass();
1913819139

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11395,7 +11395,9 @@ void Sema::CheckExplicitObjectMemberFunction(Declarator &D,
1139511395
<< ExplicitObjectParam->getSourceRange();
1139611396
}
1139711397

11398-
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) {
11398+
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
11399+
(D.getContext() == clang::DeclaratorContext::Member &&
11400+
D.isStaticMember())) {
1139911401
Diag(ExplicitObjectParam->getBeginLoc(),
1140011402
diag::err_explicit_object_parameter_nonmember)
1140111403
<< D.getSourceRange() << /*static=*/0 << IsLambda;

clang/test/CXX/drs/dr17xx.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ namespace dr1715 { // dr1715: 3.9
4646
#endif
4747
}
4848

49-
namespace dr1719 { // dr1719: no
49+
namespace dr1719 { // dr1719: 19
5050
#if __cplusplus >= 201103L
5151
struct CStruct {
5252
int one;
@@ -66,11 +66,11 @@ struct CStructWithQualifiers {
6666
static_assert(__is_layout_compatible(CStruct, const CStruct2), "");
6767
static_assert(__is_layout_compatible(CStruct, volatile CStruct2), "");
6868
static_assert(__is_layout_compatible(const CStruct, volatile CStruct2), "");
69-
// FIXME: all of the following pairs of types are layout-compatible
70-
static_assert(!__is_layout_compatible(int, const int), "");
71-
static_assert(!__is_layout_compatible(int, volatile int), "");
72-
static_assert(!__is_layout_compatible(const int, volatile int), "");
73-
static_assert(!__is_layout_compatible(CStruct, CStructWithQualifiers), "");
69+
static_assert(__is_layout_compatible(int, const int), "");
70+
static_assert(__is_layout_compatible(int, volatile int), "");
71+
static_assert(__is_layout_compatible(const int, volatile int), "");
72+
static_assert(__is_layout_compatible(CStruct, CStructWithQualifiers), "");
73+
static_assert(__is_layout_compatible(int[], const volatile int[]), "");
7474
#endif
7575
} // namespace dr1719
7676

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2p1 -fsyntax-only -verify %s
2+
3+
// REQUIRES: aarch64-registered-target
4+
#include "arm_sme.h"
5+
6+
svuint8x2_t test_sme2p1(svuint8x2_t x) {
7+
// expected-no-diagnostics
8+
return x;
9+
}
10+

clang/test/SemaCXX/cxx2b-deducing-this.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ struct S {
1616
static void f(this auto); // expected-error{{an explicit object parameter cannot appear in a static function}}
1717
virtual void f(this S); // expected-error{{an explicit object parameter cannot appear in a virtual function}}
1818

19+
// new and delete are implicitly static
20+
void *operator new(this unsigned long); // expected-error{{an explicit object parameter cannot appear in a static function}}
21+
void operator delete(this void*); // expected-error{{an explicit object parameter cannot appear in a static function}}
22+
1923
void g(this auto) const; // expected-error{{explicit object member function cannot have 'const' qualifier}}
2024
void h(this auto) &; // expected-error{{explicit object member function cannot have '&' qualifier}}
2125
void i(this auto) &&; // expected-error{{explicit object member function cannot have '&&' qualifier}}

0 commit comments

Comments
 (0)