[clang] [Clang] [C23] Fix typeof_unqual for qualified array types (PR #92767)
Mital Ashok via cfe-commits
cfe-commits at lists.llvm.org
Sat Jun 29 04:11:08 PDT 2024
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 <mital at mitalashok.co.uk>
Date: Mon, 20 May 2024 15:58:58 +0100
Subject: [PATCH 1/5] [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<ASTContext> {
///
/// \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 &Quals);
+ QualType getUnqualifiedArrayType(QualType T, Qualifiers &Quals) 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 &ctx) 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 &Context;
protected:
friend class ASTContext; // ASTContext creates these.
- TypeOfExprType(Expr *E, TypeOfKind Kind, QualType Can = QualType());
+ TypeOfExprType(const ASTContext &Context, 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<TypeOfKind>(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 &Context, Expr *E, TypeOfKind Kind)
+ : TypeOfExprType(Context, E, Kind) {}
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
Profile(ID, Context, getUnderlyingExpr(),
@@ -5323,32 +5329,23 @@ class TypeOfType : public Type {
friend class ASTContext; // ASTContext creates these.
QualType TOType;
+ const ASTContext &Context;
- 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 &Context, 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
- : TypeOfKind::Qualified;
+ return static_cast<TypeOfKind>(TypeOfBits.Kind);
}
static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; }
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 8fc2bb8c401c2..ddad2ae355487 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5682,19 +5682,19 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr, TypeOfKind Kind) const {
if (Canon) {
// We already have a "canonical" version of an identical, dependent
// typeof(expr) type. Use that as our canonical type.
- toe = new (*this, alignof(TypeOfExprType))
- TypeOfExprType(tofExpr, Kind, QualType((TypeOfExprType *)Canon, 0));
+ toe = new (*this, alignof(TypeOfExprType)) TypeOfExprType(
+ *this, tofExpr, Kind, QualType((TypeOfExprType *)Canon, 0));
} else {
// Build a new, canonical typeof(expr) type.
Canon = new (*this, alignof(DependentTypeOfExprType))
- DependentTypeOfExprType(tofExpr, Kind);
+ DependentTypeOfExprType(*this, tofExpr, Kind);
DependentTypeOfExprTypes.InsertNode(Canon, InsertPos);
toe = Canon;
}
} else {
QualType Canonical = getCanonicalType(tofExpr->getType());
toe = new (*this, alignof(TypeOfExprType))
- TypeOfExprType(tofExpr, Kind, Canonical);
+ TypeOfExprType(*this, tofExpr, Kind, Canonical);
}
Types.push_back(toe);
return QualType(toe, 0);
@@ -5707,8 +5707,8 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr, TypeOfKind Kind) const {
/// on canonical types (which are always unique).
QualType ASTContext::getTypeOfType(QualType tofType, TypeOfKind Kind) const {
QualType Canonical = getCanonicalType(tofType);
- auto *tot =
- new (*this, alignof(TypeOfType)) TypeOfType(tofType, Canonical, Kind);
+ auto *tot = new (*this, alignof(TypeOfType))
+ TypeOfType(*this, tofType, Canonical, Kind);
Types.push_back(tot);
return QualType(tot, 0);
}
@@ -6093,7 +6093,7 @@ CanQualType ASTContext::getCanonicalParamType(QualType T) const {
}
QualType ASTContext::getUnqualifiedArrayType(QualType type,
- Qualifiers &quals) {
+ Qualifiers &quals) const {
SplitQualType splitType = type.getSplitUnqualifiedType();
// FIXME: getSplitUnqualifiedType() actually walks all the way to
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index e31741cd44240..a84221233dd26 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -1617,9 +1617,10 @@ QualType QualType::stripObjCKindOfType(const ASTContext &constCtx) const {
}
QualType QualType::getAtomicUnqualifiedType() const {
- if (const auto AT = getTypePtr()->getAs<AtomicType>())
- return AT->getValueType().getUnqualifiedType();
- return getUnqualifiedType();
+ QualType T = *this;
+ if (const auto AT = T.getTypePtr()->getAs<AtomicType>())
+ T = AT->getValueType();
+ return T.getUnqualifiedType();
}
std::optional<ArrayRef<QualType>>
@@ -3860,18 +3861,19 @@ QualType MacroQualifiedType::getModifiedType() const {
return Inner;
}
-TypeOfExprType::TypeOfExprType(Expr *E, TypeOfKind Kind, QualType Can)
+TypeOfExprType::TypeOfExprType(const ASTContext &Context, Expr *E,
+ TypeOfKind Kind, QualType Can)
: Type(TypeOfExpr,
// We have to protect against 'Can' being invalid through its
// default argument.
Kind == TypeOfKind::Unqualified && !Can.isNull()
- ? Can.getAtomicUnqualifiedType()
+ ? Context.getUnqualifiedArrayType(Can.getAtomicUnqualifiedType())
: Can,
toTypeDependence(E->getDependence()) |
(E->getType()->getDependence() &
TypeDependence::VariablyModified)),
- TOExpr(E) {
- TypeOfBits.IsUnqual = Kind == TypeOfKind::Unqualified;
+ TOExpr(E), Context(Context) {
+ TypeOfBits.Kind = static_cast<unsigned>(Kind);
}
bool TypeOfExprType::isSugared() const {
@@ -3881,7 +3883,9 @@ bool TypeOfExprType::isSugared() const {
QualType TypeOfExprType::desugar() const {
if (isSugared()) {
QualType QT = getUnderlyingExpr()->getType();
- return TypeOfBits.IsUnqual ? QT.getAtomicUnqualifiedType() : QT;
+ return getKind() == TypeOfKind::Unqualified
+ ? Context.getUnqualifiedArrayType(QT.getAtomicUnqualifiedType())
+ : QT;
}
return QualType(this, 0);
}
@@ -3893,6 +3897,24 @@ void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID,
ID.AddBoolean(IsUnqual);
}
+TypeOfType::TypeOfType(const ASTContext &Context, QualType T, QualType Can,
+ TypeOfKind Kind)
+ : Type(TypeOf,
+ Kind == TypeOfKind::Unqualified
+ ? Context.getUnqualifiedArrayType(Can.getAtomicUnqualifiedType())
+ : Can,
+ T->getDependence()),
+ TOType(T), Context(Context) {
+ TypeOfBits.Kind = static_cast<unsigned>(Kind);
+}
+
+QualType TypeOfType::desugar() const {
+ QualType QT = getUnmodifiedType();
+ return getKind() == TypeOfKind::Unqualified
+ ? Context.getUnqualifiedArrayType(QT.getAtomicUnqualifiedType())
+ : QT;
+}
+
DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
// C++11 [temp.type]p2: "If an expression e involves a template parameter,
// decltype(e) denotes a unique dependent type." Hence a decltype type is
diff --git a/clang/test/Sema/c2x-typeof.c b/clang/test/Sema/c2x-typeof.c
index cf985c244f4a4..7da25aec4d3f6 100644
--- a/clang/test/Sema/c2x-typeof.c
+++ b/clang/test/Sema/c2x-typeof.c
@@ -92,3 +92,28 @@ extern __attribute__((address_space(0))) int type_attr_test_2; // expec
void invalid_param_fn(__attribute__((address_space(1))) int i); // expected-error {{parameter may not be qualified with an address space}}
typeof(invalid_param_fn) invalid_param_1;
typeof_unqual(invalid_param_fn) invalid_param_2;
+
+// Ensure restrict is stripped
+extern int *restrict p1;
+extern int *p2;
+extern typeof(p1) p1;
+extern typeof_unqual(p1) p2;
+
+// Ensure array qualifications are removed
+extern const int aci[2];
+extern const int acii[2][2];
+extern int ai[2];
+extern int aii[2][2];
+extern typeof(aci) aci;
+extern typeof_unqual(aci) ai;
+extern typeof(acii) acii;
+extern typeof_unqual(acii) aii;
+
+extern int *restrict arpi[2];
+extern int *restrict arpii[2][2];
+extern int *api[2];
+extern int *apii[2][2];
+extern typeof(arpi) arpi;
+extern typeof_unqual(arpi) api;
+extern typeof(arpii) arpii;
+extern typeof_unqual(arpii) apii;
>From a30591f68bee7b5904d43c300aa3c09d3b388075 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Mon, 20 May 2024 16:37:40 +0100
Subject: [PATCH 2/5] Fix handling arrays of _Atomic types
---
clang/include/clang/AST/ASTContext.h | 8 +++++
clang/include/clang/AST/Type.h | 2 +-
clang/lib/AST/ASTContext.cpp | 54 ++++++++++++++++++++--------
clang/lib/AST/Type.cpp | 8 ++---
clang/test/Sema/c2x-typeof.c | 7 ++++
5 files changed, 59 insertions(+), 20 deletions(-)
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index ff7bdb7e7e1a6..6c4a3c0729521 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -2617,6 +2617,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
return getUnqualifiedArrayType(T, Quals);
}
+ QualType getAtomicUnqualifiedArrayType(QualType T, Qualifiers &Quals,
+ bool &WasAtomic) const;
+ QualType getAtomicUnqualifiedArrayType(QualType T) const {
+ Qualifiers Quals;
+ bool WasAtomic;
+ return getAtomicUnqualifiedArrayType(T, Quals, WasAtomic);
+ }
+
/// Determine whether the given types are equivalent after
/// cvr-qualifiers have been removed.
bool hasSameUnqualifiedType(QualType T1, QualType T2) const {
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index df7f396bae095..5b5c7558e9692 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1608,7 +1608,7 @@ class QualType {
///
/// 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.
+ /// type, use ASTContext::getAtomicUnqualifiedArrayType.
QualType getAtomicUnqualifiedType() const;
private:
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index ddad2ae355487..6a9a64030e7b1 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -6092,8 +6092,10 @@ CanQualType ASTContext::getCanonicalParamType(QualType T) const {
return CanQualType::CreateUnsafe(Result);
}
-QualType ASTContext::getUnqualifiedArrayType(QualType type,
- Qualifiers &quals) const {
+namespace {
+template <bool RemoveAtomic>
+QualType getUnqualifiedArrayType(const ASTContext &C, QualType type,
+ Qualifiers &quals, bool *WasAtomic = nullptr) {
SplitQualType splitType = type.getSplitUnqualifiedType();
// FIXME: getSplitUnqualifiedType() actually walks all the way to
@@ -6106,12 +6108,22 @@ QualType ASTContext::getUnqualifiedArrayType(QualType type,
// If we don't have an array, just use the results in splitType.
if (!AT) {
quals = splitType.Quals;
- return QualType(splitType.Ty, 0);
+ QualType Unqual(splitType.Ty, 0);
+ if constexpr (RemoveAtomic) {
+ if (const auto *AtT = Unqual->getAs<AtomicType>()) {
+ *WasAtomic = true;
+ Unqual = AtT->getValueType();
+ } else {
+ *WasAtomic = false;
+ }
+ }
+ return Unqual;
}
// Otherwise, recurse on the array's element type.
QualType elementType = AT->getElementType();
- QualType unqualElementType = getUnqualifiedArrayType(elementType, quals);
+ QualType unqualElementType =
+ getUnqualifiedArrayType<RemoveAtomic>(C, elementType, quals, WasAtomic);
// If that didn't change the element type, AT has no qualifiers, so we
// can just use the results in splitType.
@@ -6126,26 +6138,38 @@ QualType ASTContext::getUnqualifiedArrayType(QualType type,
quals.addConsistentQualifiers(splitType.Quals);
if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
- return getConstantArrayType(unqualElementType, CAT->getSize(),
- CAT->getSizeExpr(), CAT->getSizeModifier(), 0);
+ return C.getConstantArrayType(unqualElementType, CAT->getSize(),
+ CAT->getSizeExpr(), CAT->getSizeModifier(),
+ 0);
}
if (const auto *IAT = dyn_cast<IncompleteArrayType>(AT)) {
- return getIncompleteArrayType(unqualElementType, IAT->getSizeModifier(), 0);
+ return C.getIncompleteArrayType(unqualElementType, IAT->getSizeModifier(),
+ 0);
}
if (const auto *VAT = dyn_cast<VariableArrayType>(AT)) {
- return getVariableArrayType(unqualElementType,
- VAT->getSizeExpr(),
- VAT->getSizeModifier(),
- VAT->getIndexTypeCVRQualifiers(),
- VAT->getBracketsRange());
+ return C.getVariableArrayType(
+ unqualElementType, VAT->getSizeExpr(), VAT->getSizeModifier(),
+ VAT->getIndexTypeCVRQualifiers(), VAT->getBracketsRange());
}
const auto *DSAT = cast<DependentSizedArrayType>(AT);
- return getDependentSizedArrayType(unqualElementType, DSAT->getSizeExpr(),
- DSAT->getSizeModifier(), 0,
- SourceRange());
+ return C.getDependentSizedArrayType(unqualElementType, DSAT->getSizeExpr(),
+ DSAT->getSizeModifier(), 0,
+ SourceRange());
+}
+} // namespace
+
+QualType ASTContext::getUnqualifiedArrayType(QualType Type,
+ Qualifiers &Quals) const {
+ return ::getUnqualifiedArrayType<false>(*this, Type, Quals);
+}
+
+QualType ASTContext::getAtomicUnqualifiedArrayType(QualType Type,
+ Qualifiers &Quals,
+ bool &WasAtomic) const {
+ return ::getUnqualifiedArrayType<true>(*this, Type, Quals, &WasAtomic);
}
/// Attempt to unwrap two types that may both be array types with the same bound
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index a84221233dd26..253c4f24f4c73 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -3867,7 +3867,7 @@ TypeOfExprType::TypeOfExprType(const ASTContext &Context, Expr *E,
// We have to protect against 'Can' being invalid through its
// default argument.
Kind == TypeOfKind::Unqualified && !Can.isNull()
- ? Context.getUnqualifiedArrayType(Can.getAtomicUnqualifiedType())
+ ? Context.getAtomicUnqualifiedArrayType(Can)
: Can,
toTypeDependence(E->getDependence()) |
(E->getType()->getDependence() &
@@ -3884,7 +3884,7 @@ QualType TypeOfExprType::desugar() const {
if (isSugared()) {
QualType QT = getUnderlyingExpr()->getType();
return getKind() == TypeOfKind::Unqualified
- ? Context.getUnqualifiedArrayType(QT.getAtomicUnqualifiedType())
+ ? Context.getAtomicUnqualifiedArrayType(QT)
: QT;
}
return QualType(this, 0);
@@ -3901,7 +3901,7 @@ TypeOfType::TypeOfType(const ASTContext &Context, QualType T, QualType Can,
TypeOfKind Kind)
: Type(TypeOf,
Kind == TypeOfKind::Unqualified
- ? Context.getUnqualifiedArrayType(Can.getAtomicUnqualifiedType())
+ ? Context.getAtomicUnqualifiedArrayType(Can)
: Can,
T->getDependence()),
TOType(T), Context(Context) {
@@ -3911,7 +3911,7 @@ TypeOfType::TypeOfType(const ASTContext &Context, QualType T, QualType Can,
QualType TypeOfType::desugar() const {
QualType QT = getUnmodifiedType();
return getKind() == TypeOfKind::Unqualified
- ? Context.getUnqualifiedArrayType(QT.getAtomicUnqualifiedType())
+ ? Context.getAtomicUnqualifiedArrayType(QT)
: QT;
}
diff --git a/clang/test/Sema/c2x-typeof.c b/clang/test/Sema/c2x-typeof.c
index 7da25aec4d3f6..52e6914d1c05e 100644
--- a/clang/test/Sema/c2x-typeof.c
+++ b/clang/test/Sema/c2x-typeof.c
@@ -117,3 +117,10 @@ extern typeof(arpi) arpi;
extern typeof_unqual(arpi) api;
extern typeof(arpii) arpii;
extern typeof_unqual(arpii) apii;
+
+extern int _Atomic aAi[2];
+extern int _Atomic aAii[2][2];
+extern typeof(aAi) aAi;
+extern typeof_unqual(aAi) ai;
+extern typeof(aAii) aAii;
+extern typeof_unqual(aAii) aii;
>From 4609f91fdddde3a040db40a209471ae8f8c80db5 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Mon, 20 May 2024 16:51:44 +0100
Subject: [PATCH 3/5] Add relase note
---
clang/docs/ReleaseNotes.rst | 2 ++
1 file changed, 2 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5a123b0b86dda..f8a4447542200 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -589,6 +589,8 @@ Bug Fixes in This Version
- ``__is_array`` and ``__is_bounded_array`` no longer return ``true`` for
zero-sized arrays. Fixes (#GH54705).
+- ``typeof_unqual`` now properly removes type qualifiers from arrays and their element types. (#GH92667)
+
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>From 7ec82801979c317125a3068a67cd3bf07f8767ff Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Tue, 21 May 2024 15:55:02 +0100
Subject: [PATCH 4/5] Add example from issue
---
clang/test/Sema/c2x-typeof.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/clang/test/Sema/c2x-typeof.c b/clang/test/Sema/c2x-typeof.c
index 52e6914d1c05e..662c321d727b9 100644
--- a/clang/test/Sema/c2x-typeof.c
+++ b/clang/test/Sema/c2x-typeof.c
@@ -124,3 +124,11 @@ extern typeof(aAi) aAi;
extern typeof_unqual(aAi) ai;
extern typeof(aAii) aAii;
extern typeof_unqual(aAii) aii;
+
+const char* const animals[] = { "aardvark", "bluejay", "catte" };
+void GH92667(void) {
+ const char* animals2_array1[3];
+ typeof_unqual(animals) animals2_array;
+ animals2_array1[0] = 0;
+ animals2_array[0] = 0;
+}
>From 619260922e850fd3b6fffe012783db50ed0795a8 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Thu, 30 May 2024 22:18:49 +0100
Subject: [PATCH 5/5] Don't remove _Atomic of element types of arrays which are
not atomic
---
clang/include/clang/AST/ASTContext.h | 8 -----
clang/include/clang/AST/Type.h | 2 +-
clang/lib/AST/ASTContext.cpp | 54 ++++++++--------------------
clang/lib/AST/Type.cpp | 8 ++---
clang/test/Sema/c2x-typeof.c | 11 ++++--
5 files changed, 29 insertions(+), 54 deletions(-)
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index c36423b3ac750..5f1b8c7ac7b57 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -2626,14 +2626,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
return getUnqualifiedArrayType(T, Quals);
}
- QualType getAtomicUnqualifiedArrayType(QualType T, Qualifiers &Quals,
- bool &WasAtomic) const;
- QualType getAtomicUnqualifiedArrayType(QualType T) const {
- Qualifiers Quals;
- bool WasAtomic;
- return getAtomicUnqualifiedArrayType(T, Quals, WasAtomic);
- }
-
/// Determine whether the given types are equivalent after
/// cvr-qualifiers have been removed.
bool hasSameUnqualifiedType(QualType T1, QualType T2) const {
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 072051eb5990d..45ad1464a43ba 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1608,7 +1608,7 @@ class QualType {
///
/// 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::getAtomicUnqualifiedArrayType.
+ /// type, use in conjunction with ASTContext::getUnqualifiedArrayType.
QualType getAtomicUnqualifiedType() const;
private:
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index f1bbefe54120b..07d92f8697ff9 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -6093,10 +6093,8 @@ CanQualType ASTContext::getCanonicalParamType(QualType T) const {
return CanQualType::CreateUnsafe(Result);
}
-namespace {
-template <bool RemoveAtomic>
-QualType getUnqualifiedArrayType(const ASTContext &C, QualType type,
- Qualifiers &quals, bool *WasAtomic = nullptr) {
+QualType ASTContext::getUnqualifiedArrayType(QualType type,
+ Qualifiers &quals) const {
SplitQualType splitType = type.getSplitUnqualifiedType();
// FIXME: getSplitUnqualifiedType() actually walks all the way to
@@ -6109,22 +6107,12 @@ QualType getUnqualifiedArrayType(const ASTContext &C, QualType type,
// If we don't have an array, just use the results in splitType.
if (!AT) {
quals = splitType.Quals;
- QualType Unqual(splitType.Ty, 0);
- if constexpr (RemoveAtomic) {
- if (const auto *AtT = Unqual->getAs<AtomicType>()) {
- *WasAtomic = true;
- Unqual = AtT->getValueType();
- } else {
- *WasAtomic = false;
- }
- }
- return Unqual;
+ return QualType(splitType.Ty, 0);
}
// Otherwise, recurse on the array's element type.
QualType elementType = AT->getElementType();
- QualType unqualElementType =
- getUnqualifiedArrayType<RemoveAtomic>(C, elementType, quals, WasAtomic);
+ QualType unqualElementType = getUnqualifiedArrayType(elementType, quals);
// If that didn't change the element type, AT has no qualifiers, so we
// can just use the results in splitType.
@@ -6139,38 +6127,26 @@ QualType getUnqualifiedArrayType(const ASTContext &C, QualType type,
quals.addConsistentQualifiers(splitType.Quals);
if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
- return C.getConstantArrayType(unqualElementType, CAT->getSize(),
- CAT->getSizeExpr(), CAT->getSizeModifier(),
- 0);
+ return getConstantArrayType(unqualElementType, CAT->getSize(),
+ CAT->getSizeExpr(), CAT->getSizeModifier(), 0);
}
if (const auto *IAT = dyn_cast<IncompleteArrayType>(AT)) {
- return C.getIncompleteArrayType(unqualElementType, IAT->getSizeModifier(),
- 0);
+ return getIncompleteArrayType(unqualElementType, IAT->getSizeModifier(), 0);
}
if (const auto *VAT = dyn_cast<VariableArrayType>(AT)) {
- return C.getVariableArrayType(
- unqualElementType, VAT->getSizeExpr(), VAT->getSizeModifier(),
- VAT->getIndexTypeCVRQualifiers(), VAT->getBracketsRange());
+ return getVariableArrayType(unqualElementType,
+ VAT->getSizeExpr(),
+ VAT->getSizeModifier(),
+ VAT->getIndexTypeCVRQualifiers(),
+ VAT->getBracketsRange());
}
const auto *DSAT = cast<DependentSizedArrayType>(AT);
- return C.getDependentSizedArrayType(unqualElementType, DSAT->getSizeExpr(),
- DSAT->getSizeModifier(), 0,
- SourceRange());
-}
-} // namespace
-
-QualType ASTContext::getUnqualifiedArrayType(QualType Type,
- Qualifiers &Quals) const {
- return ::getUnqualifiedArrayType<false>(*this, Type, Quals);
-}
-
-QualType ASTContext::getAtomicUnqualifiedArrayType(QualType Type,
- Qualifiers &Quals,
- bool &WasAtomic) const {
- return ::getUnqualifiedArrayType<true>(*this, Type, Quals, &WasAtomic);
+ return getDependentSizedArrayType(unqualElementType, DSAT->getSizeExpr(),
+ DSAT->getSizeModifier(), 0,
+ SourceRange());
}
/// Attempt to unwrap two types that may both be array types with the same bound
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 20c666cda64b4..c6de1cb7ecd66 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -3885,7 +3885,7 @@ TypeOfExprType::TypeOfExprType(const ASTContext &Context, Expr *E,
// We have to protect against 'Can' being invalid through its
// default argument.
Kind == TypeOfKind::Unqualified && !Can.isNull()
- ? Context.getAtomicUnqualifiedArrayType(Can)
+ ? Context.getUnqualifiedArrayType(Can).getAtomicUnqualifiedType()
: Can,
toTypeDependence(E->getDependence()) |
(E->getType()->getDependence() &
@@ -3902,7 +3902,7 @@ QualType TypeOfExprType::desugar() const {
if (isSugared()) {
QualType QT = getUnderlyingExpr()->getType();
return getKind() == TypeOfKind::Unqualified
- ? Context.getAtomicUnqualifiedArrayType(QT)
+ ? Context.getUnqualifiedArrayType(QT).getAtomicUnqualifiedType()
: QT;
}
return QualType(this, 0);
@@ -3919,7 +3919,7 @@ TypeOfType::TypeOfType(const ASTContext &Context, QualType T, QualType Can,
TypeOfKind Kind)
: Type(TypeOf,
Kind == TypeOfKind::Unqualified
- ? Context.getAtomicUnqualifiedArrayType(Can)
+ ? Context.getUnqualifiedArrayType(Can).getAtomicUnqualifiedType()
: Can,
T->getDependence()),
TOType(T), Context(Context) {
@@ -3929,7 +3929,7 @@ TypeOfType::TypeOfType(const ASTContext &Context, QualType T, QualType Can,
QualType TypeOfType::desugar() const {
QualType QT = getUnmodifiedType();
return getKind() == TypeOfKind::Unqualified
- ? Context.getAtomicUnqualifiedArrayType(QT)
+ ? Context.getUnqualifiedArrayType(QT).getAtomicUnqualifiedType()
: QT;
}
diff --git a/clang/test/Sema/c2x-typeof.c b/clang/test/Sema/c2x-typeof.c
index 662c321d727b9..2cc3f57b509d4 100644
--- a/clang/test/Sema/c2x-typeof.c
+++ b/clang/test/Sema/c2x-typeof.c
@@ -121,9 +121,16 @@ extern typeof_unqual(arpii) apii;
extern int _Atomic aAi[2];
extern int _Atomic aAii[2][2];
extern typeof(aAi) aAi;
-extern typeof_unqual(aAi) ai;
+extern typeof_unqual(aAi) aAi;
extern typeof(aAii) aAii;
-extern typeof_unqual(aAii) aii;
+extern typeof_unqual(aAii) aAii;
+
+extern _Atomic(int) aAi[2];
+extern _Atomic(int) aAii[2][2];
+extern typeof(aAi) aAi;
+extern typeof_unqual(aAi) aAi;
+extern typeof(aAii) aAii;
+extern typeof_unqual(aAii) aAii;
const char* const animals[] = { "aardvark", "bluejay", "catte" };
void GH92667(void) {
More information about the cfe-commits
mailing list