Skip to content

Commit a56e009

Browse files
MitalAshokcor3ntin
andauthored
[Clang] [C23] Fix typeof_unqual for qualified array types (#92767)
Properly remove qualifiers for both the element type and the array type Fixes #92667 --------- Co-authored-by: cor3ntin <[email protected]>
1 parent c034c44 commit a56e009

File tree

6 files changed

+106
-34
lines changed

6 files changed

+106
-34
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,8 @@ Bug Fixes in This Version
838838
- ``__has_unique_object_representations`` correctly handles arrays of unknown bounds of
839839
types by ensuring they are complete and instantiating them if needed. Fixes (#GH95311).
840840

841+
- ``typeof_unqual`` now properly removes type qualifiers from arrays and their element types. (#GH92667)
842+
841843
Bug Fixes to Compiler Builtins
842844
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
843845

clang/include/clang/AST/ASTContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2653,6 +2653,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
26532653
/// \returns if this is an array type, the completely unqualified array type
26542654
/// that corresponds to it. Otherwise, returns T.getUnqualifiedType().
26552655
QualType getUnqualifiedArrayType(QualType T, Qualifiers &Quals) const;
2656+
QualType getUnqualifiedArrayType(QualType T) const {
2657+
Qualifiers Quals;
2658+
return getUnqualifiedArrayType(T, Quals);
2659+
}
26562660

26572661
/// Determine whether the given types are equivalent after
26582662
/// cvr-qualifiers have been removed.

clang/include/clang/AST/Type.h

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,6 +1618,10 @@ class QualType {
16181618
QualType stripObjCKindOfType(const ASTContext &ctx) const;
16191619

16201620
/// Remove all qualifiers including _Atomic.
1621+
///
1622+
/// Like getUnqualifiedType(), the type may still be qualified if it is a
1623+
/// sugared array type. To strip qualifiers even from within a sugared array
1624+
/// type, use in conjunction with ASTContext::getUnqualifiedArrayType.
16211625
QualType getAtomicUnqualifiedType() const;
16221626

16231627
private:
@@ -2105,8 +2109,8 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
21052109

21062110
LLVM_PREFERRED_TYPE(TypeBitfields)
21072111
unsigned : NumTypeBits;
2108-
LLVM_PREFERRED_TYPE(bool)
2109-
unsigned IsUnqual : 1; // If true: typeof_unqual, else: typeof
2112+
LLVM_PREFERRED_TYPE(TypeOfKind)
2113+
unsigned Kind : 1;
21102114
};
21112115

21122116
class UsingBitfields {
@@ -5661,19 +5665,20 @@ class MacroQualifiedType : public Type {
56615665
/// extension) or a `typeof_unqual` expression (a C23 feature).
56625666
class TypeOfExprType : public Type {
56635667
Expr *TOExpr;
5668+
const ASTContext &Context;
56645669

56655670
protected:
56665671
friend class ASTContext; // ASTContext creates these.
56675672

5668-
TypeOfExprType(Expr *E, TypeOfKind Kind, QualType Can = QualType());
5673+
TypeOfExprType(const ASTContext &Context, Expr *E, TypeOfKind Kind,
5674+
QualType Can = QualType());
56695675

56705676
public:
56715677
Expr *getUnderlyingExpr() const { return TOExpr; }
56725678

56735679
/// Returns the kind of 'typeof' type this is.
56745680
TypeOfKind getKind() const {
5675-
return TypeOfBits.IsUnqual ? TypeOfKind::Unqualified
5676-
: TypeOfKind::Qualified;
5681+
return static_cast<TypeOfKind>(TypeOfBits.Kind);
56775682
}
56785683

56795684
/// Remove a single level of sugar.
@@ -5694,7 +5699,8 @@ class TypeOfExprType : public Type {
56945699
class DependentTypeOfExprType : public TypeOfExprType,
56955700
public llvm::FoldingSetNode {
56965701
public:
5697-
DependentTypeOfExprType(Expr *E, TypeOfKind Kind) : TypeOfExprType(E, Kind) {}
5702+
DependentTypeOfExprType(const ASTContext &Context, Expr *E, TypeOfKind Kind)
5703+
: TypeOfExprType(Context, E, Kind) {}
56985704

56995705
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
57005706
Profile(ID, Context, getUnderlyingExpr(),
@@ -5711,32 +5717,23 @@ class TypeOfType : public Type {
57115717
friend class ASTContext; // ASTContext creates these.
57125718

57135719
QualType TOType;
5720+
const ASTContext &Context;
57145721

5715-
TypeOfType(QualType T, QualType Can, TypeOfKind Kind)
5716-
: Type(TypeOf,
5717-
Kind == TypeOfKind::Unqualified ? Can.getAtomicUnqualifiedType()
5718-
: Can,
5719-
T->getDependence()),
5720-
TOType(T) {
5721-
TypeOfBits.IsUnqual = Kind == TypeOfKind::Unqualified;
5722-
}
5722+
TypeOfType(const ASTContext &Context, QualType T, QualType Can,
5723+
TypeOfKind Kind);
57235724

57245725
public:
57255726
QualType getUnmodifiedType() const { return TOType; }
57265727

57275728
/// Remove a single level of sugar.
5728-
QualType desugar() const {
5729-
QualType QT = getUnmodifiedType();
5730-
return TypeOfBits.IsUnqual ? QT.getAtomicUnqualifiedType() : QT;
5731-
}
5729+
QualType desugar() const;
57325730

57335731
/// Returns whether this type directly provides sugar.
57345732
bool isSugared() const { return true; }
57355733

57365734
/// Returns the kind of 'typeof' type this is.
57375735
TypeOfKind getKind() const {
5738-
return TypeOfBits.IsUnqual ? TypeOfKind::Unqualified
5739-
: TypeOfKind::Qualified;
5736+
return static_cast<TypeOfKind>(TypeOfBits.Kind);
57405737
}
57415738

57425739
static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; }

clang/lib/AST/ASTContext.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6020,19 +6020,19 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr, TypeOfKind Kind) const {
60206020
if (Canon) {
60216021
// We already have a "canonical" version of an identical, dependent
60226022
// typeof(expr) type. Use that as our canonical type.
6023-
toe = new (*this, alignof(TypeOfExprType))
6024-
TypeOfExprType(tofExpr, Kind, QualType((TypeOfExprType *)Canon, 0));
6023+
toe = new (*this, alignof(TypeOfExprType)) TypeOfExprType(
6024+
*this, tofExpr, Kind, QualType((TypeOfExprType *)Canon, 0));
60256025
} else {
60266026
// Build a new, canonical typeof(expr) type.
60276027
Canon = new (*this, alignof(DependentTypeOfExprType))
6028-
DependentTypeOfExprType(tofExpr, Kind);
6028+
DependentTypeOfExprType(*this, tofExpr, Kind);
60296029
DependentTypeOfExprTypes.InsertNode(Canon, InsertPos);
60306030
toe = Canon;
60316031
}
60326032
} else {
60336033
QualType Canonical = getCanonicalType(tofExpr->getType());
60346034
toe = new (*this, alignof(TypeOfExprType))
6035-
TypeOfExprType(tofExpr, Kind, Canonical);
6035+
TypeOfExprType(*this, tofExpr, Kind, Canonical);
60366036
}
60376037
Types.push_back(toe);
60386038
return QualType(toe, 0);
@@ -6045,8 +6045,8 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr, TypeOfKind Kind) const {
60456045
/// on canonical types (which are always unique).
60466046
QualType ASTContext::getTypeOfType(QualType tofType, TypeOfKind Kind) const {
60476047
QualType Canonical = getCanonicalType(tofType);
6048-
auto *tot =
6049-
new (*this, alignof(TypeOfType)) TypeOfType(tofType, Canonical, Kind);
6048+
auto *tot = new (*this, alignof(TypeOfType))
6049+
TypeOfType(*this, tofType, Canonical, Kind);
60506050
Types.push_back(tot);
60516051
return QualType(tot, 0);
60526052
}

clang/lib/AST/Type.cpp

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,9 +1627,10 @@ QualType QualType::stripObjCKindOfType(const ASTContext &constCtx) const {
16271627
}
16281628

16291629
QualType QualType::getAtomicUnqualifiedType() const {
1630-
if (const auto AT = getTypePtr()->getAs<AtomicType>())
1631-
return AT->getValueType().getUnqualifiedType();
1632-
return getUnqualifiedType();
1630+
QualType T = *this;
1631+
if (const auto AT = T.getTypePtr()->getAs<AtomicType>())
1632+
T = AT->getValueType();
1633+
return T.getUnqualifiedType();
16331634
}
16341635

16351636
std::optional<ArrayRef<QualType>>
@@ -3890,18 +3891,19 @@ QualType MacroQualifiedType::getModifiedType() const {
38903891
return Inner;
38913892
}
38923893

3893-
TypeOfExprType::TypeOfExprType(Expr *E, TypeOfKind Kind, QualType Can)
3894+
TypeOfExprType::TypeOfExprType(const ASTContext &Context, Expr *E,
3895+
TypeOfKind Kind, QualType Can)
38943896
: Type(TypeOfExpr,
38953897
// We have to protect against 'Can' being invalid through its
38963898
// default argument.
38973899
Kind == TypeOfKind::Unqualified && !Can.isNull()
3898-
? Can.getAtomicUnqualifiedType()
3900+
? Context.getUnqualifiedArrayType(Can).getAtomicUnqualifiedType()
38993901
: Can,
39003902
toTypeDependence(E->getDependence()) |
39013903
(E->getType()->getDependence() &
39023904
TypeDependence::VariablyModified)),
3903-
TOExpr(E) {
3904-
TypeOfBits.IsUnqual = Kind == TypeOfKind::Unqualified;
3905+
TOExpr(E), Context(Context) {
3906+
TypeOfBits.Kind = static_cast<unsigned>(Kind);
39053907
}
39063908

39073909
bool TypeOfExprType::isSugared() const {
@@ -3911,7 +3913,9 @@ bool TypeOfExprType::isSugared() const {
39113913
QualType TypeOfExprType::desugar() const {
39123914
if (isSugared()) {
39133915
QualType QT = getUnderlyingExpr()->getType();
3914-
return TypeOfBits.IsUnqual ? QT.getAtomicUnqualifiedType() : QT;
3916+
return getKind() == TypeOfKind::Unqualified
3917+
? Context.getUnqualifiedArrayType(QT).getAtomicUnqualifiedType()
3918+
: QT;
39153919
}
39163920
return QualType(this, 0);
39173921
}
@@ -3923,6 +3927,24 @@ void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID,
39233927
ID.AddBoolean(IsUnqual);
39243928
}
39253929

3930+
TypeOfType::TypeOfType(const ASTContext &Context, QualType T, QualType Can,
3931+
TypeOfKind Kind)
3932+
: Type(TypeOf,
3933+
Kind == TypeOfKind::Unqualified
3934+
? Context.getUnqualifiedArrayType(Can).getAtomicUnqualifiedType()
3935+
: Can,
3936+
T->getDependence()),
3937+
TOType(T), Context(Context) {
3938+
TypeOfBits.Kind = static_cast<unsigned>(Kind);
3939+
}
3940+
3941+
QualType TypeOfType::desugar() const {
3942+
QualType QT = getUnmodifiedType();
3943+
return getKind() == TypeOfKind::Unqualified
3944+
? Context.getUnqualifiedArrayType(QT).getAtomicUnqualifiedType()
3945+
: QT;
3946+
}
3947+
39263948
DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
39273949
// C++11 [temp.type]p2: "If an expression e involves a template parameter,
39283950
// decltype(e) denotes a unique dependent type." Hence a decltype type is

clang/test/Sema/c2x-typeof.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,50 @@ extern __attribute__((address_space(0))) int type_attr_test_2; // expec
9292
void invalid_param_fn(__attribute__((address_space(1))) int i); // expected-error {{parameter may not be qualified with an address space}}
9393
typeof(invalid_param_fn) invalid_param_1;
9494
typeof_unqual(invalid_param_fn) invalid_param_2;
95+
96+
// Ensure restrict is stripped
97+
extern int *restrict p1;
98+
extern int *p2;
99+
extern typeof(p1) p1;
100+
extern typeof_unqual(p1) p2;
101+
102+
// Ensure array qualifications are removed
103+
extern const int aci[2];
104+
extern const int acii[2][2];
105+
extern int ai[2];
106+
extern int aii[2][2];
107+
extern typeof(aci) aci;
108+
extern typeof_unqual(aci) ai;
109+
extern typeof(acii) acii;
110+
extern typeof_unqual(acii) aii;
111+
112+
extern int *restrict arpi[2];
113+
extern int *restrict arpii[2][2];
114+
extern int *api[2];
115+
extern int *apii[2][2];
116+
extern typeof(arpi) arpi;
117+
extern typeof_unqual(arpi) api;
118+
extern typeof(arpii) arpii;
119+
extern typeof_unqual(arpii) apii;
120+
121+
extern int _Atomic aAi[2];
122+
extern int _Atomic aAii[2][2];
123+
extern typeof(aAi) aAi;
124+
extern typeof_unqual(aAi) aAi;
125+
extern typeof(aAii) aAii;
126+
extern typeof_unqual(aAii) aAii;
127+
128+
extern _Atomic(int) aAi[2];
129+
extern _Atomic(int) aAii[2][2];
130+
extern typeof(aAi) aAi;
131+
extern typeof_unqual(aAi) aAi;
132+
extern typeof(aAii) aAii;
133+
extern typeof_unqual(aAii) aAii;
134+
135+
const char* const animals[] = { "aardvark", "bluejay", "catte" };
136+
void GH92667(void) {
137+
const char* animals2_array1[3];
138+
typeof_unqual(animals) animals2_array;
139+
animals2_array1[0] = 0;
140+
animals2_array[0] = 0;
141+
}

0 commit comments

Comments
 (0)