[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 <corentinjabot@gmail.com>
This commit is contained in:
Mital Ashok 2024-07-17 15:58:21 +01:00 committed by GitHub
parent c034c44362
commit a56e009ef8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 106 additions and 34 deletions

View File

@ -838,6 +838,8 @@ Bug Fixes in This Version
- ``__has_unique_object_representations`` correctly handles arrays of unknown bounds of
types by ensuring they are complete and instantiating them if needed. Fixes (#GH95311).
- ``typeof_unqual`` now properly removes type qualifiers from arrays and their element types. (#GH92667)
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -2653,6 +2653,10 @@ public:
/// \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) 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.

View File

@ -1618,6 +1618,10 @@ public:
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 in conjunction with ASTContext::getUnqualifiedArrayType.
QualType getAtomicUnqualifiedType() const;
private:
@ -2105,8 +2109,8 @@ protected:
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 {
@ -5661,19 +5665,20 @@ public:
/// 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.
@ -5694,7 +5699,8 @@ public:
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(),
@ -5711,32 +5717,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; }

View File

@ -6020,19 +6020,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);
@ -6045,8 +6045,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);
}

View File

@ -1627,9 +1627,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>>
@ -3890,18 +3891,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 {
@ -3911,7 +3913,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);
}
@ -3923,6 +3927,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

View File

@ -92,3 +92,50 @@ 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;
extern int _Atomic aAi[2];
extern int _Atomic aAii[2][2];
extern typeof(aAi) aAi;
extern typeof_unqual(aAi) aAi;
extern typeof(aAii) aAii;
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) {
const char* animals2_array1[3];
typeof_unqual(animals) animals2_array;
animals2_array1[0] = 0;
animals2_array[0] = 0;
}