https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/92767
>From f87cb4c754a477515746e2ac2f8906b93ccd1fe3 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@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 <mi...@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 <mi...@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 <mi...@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 <mi...@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) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits