Skip to content

[Clang] Make the SizeType, SignedSizeType and PtrdiffType be named sugar types instead of built-in types #143653

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9628219
Enable __ptrdiff_t
YexuanXiao Jun 10, 2025
33f05ab
Enable __size_t and __unsigned_size_t
YexuanXiao Jun 11, 2025
7e2593e
Revert changes made outside the intended purpose
YexuanXiao Jun 11, 2025
bcc45f0
Add ASTContext::getCanonicalSizeType()
YexuanXiao Jun 11, 2025
9d6235b
Check typedefs are defined in the appropriate scope
YexuanXiao Jun 11, 2025
85cbd4a
Move ssize_t to the global scope, as it must ultimately be provided i…
YexuanXiao Jun 11, 2025
210fe3b
Fix code format
YexuanXiao Jun 12, 2025
ddd73d8
Clarifying support for C89
YexuanXiao Jun 12, 2025
6e207dd
Try add PredefinedSugarType
YexuanXiao Jun 13, 2025
1519032
Fix tests
YexuanXiao Jun 14, 2025
41f1433
Merge pull request #1 from YexuanXiao/predefined-sugar
YexuanXiao Jun 14, 2025
fc57313
Manually resolve conflicts
YexuanXiao Jun 14, 2025
c702c18
Add support for the new Type in FormatString
YexuanXiao Jun 14, 2025
4b62452
Enable __signed_size_t and __ptrdiff_t
YexuanXiao Jun 14, 2025
3ab170b
Update the comment to match the latest impl
YexuanXiao Jun 14, 2025
c26bb5f
Fix comment
YexuanXiao Jun 14, 2025
b53c418
Update tests to match the latest impl
YexuanXiao Jun 14, 2025
46a8ede
Fix the errors pointed out in the review
YexuanXiao Jun 14, 2025
aabc866
Fix enum-to-integer conversion
YexuanXiao Jun 14, 2025
f5acec2
Fix the test of clangd
YexuanXiao Jun 14, 2025
6d427d3
Fix code format
YexuanXiao Jun 14, 2025
b487226
Fix tests
YexuanXiao Jun 14, 2025
a60ff6e
Remove unnecessary #include added by clangd
YexuanXiao Jun 14, 2025
17ef365
Actively initialize SizeType, SignedSizeType, PtrdiffType instead of …
YexuanXiao Jun 15, 2025
dd2a256
Remove the unused function declaration and minor tweaks
YexuanXiao Jun 15, 2025
0bbc668
Use using declarations to expose protected members to simplify the code
YexuanXiao Jun 15, 2025
895efce
Resolve a conflict
YexuanXiao Jun 26, 2025
9ed218e
Temporary remove to resolve the conflict
YexuanXiao Jun 26, 2025
a60f96d
Merge branch 'main' into main
YexuanXiao Jun 26, 2025
faf82b1
Update ASTReader.cpp
YexuanXiao Jun 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 22 additions & 11 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "clang/AST/RawCommentList.h"
#include "clang/AST/SYCLKernelInfo.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceLocation.h"
Expand Down Expand Up @@ -1529,6 +1530,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// and bit count.
QualType getDependentBitIntType(bool Unsigned, Expr *BitsExpr) const;

QualType getPredefinedSugarType(uint32_t KD, QualType UnderlyingType) const;

/// Gets the struct used to keep track of the extended descriptor for
/// pointer to blocks.
QualType getBlockDescriptorExtendedType() const;
Expand Down Expand Up @@ -1952,6 +1955,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
bool IsDependent,
QualType Canon) const;

// The core language uses these types as the result types of some expressions,
// which are typically standard integer types and consistent with it's
// typedefs (if any).
mutable QualType SizeType; // __size_t
mutable QualType SignedSizeType; // __signed_size_t
mutable QualType PtrdiffType; // __ptrdiff_t
public:
/// Return the unique reference to the type for the specified TagDecl
/// (struct/union/class/enum) decl.
Expand All @@ -1961,11 +1970,22 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// <stddef.h>.
///
/// The sizeof operator requires this (C99 6.5.3.4p4).
CanQualType getSizeType() const;
QualType getSizeType() const;

CanQualType getCanonicalSizeType() const;

/// Return the unique signed counterpart of
/// the integer type corresponding to size_t.
CanQualType getSignedSizeType() const;
QualType getSignedSizeType() const;

/// Return the unique type for "ptrdiff_t" (C99 7.17) defined in
/// <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType getPointerDiffType() const;

/// Return the unique unsigned counterpart of "ptrdiff_t"
/// integer type. The standard (C11 7.21.6.1p7) refers to this type
/// in the definition of %tu format specifier.
QualType getUnsignedPointerDiffType() const;

/// Return the unique type for "intmax_t" (C99 7.18.1.5), defined in
/// <stdint.h>.
Expand Down Expand Up @@ -2006,15 +2026,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// as defined by the target.
QualType getUIntPtrType() const;

/// Return the unique type for "ptrdiff_t" (C99 7.17) defined in
/// <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType getPointerDiffType() const;

/// Return the unique unsigned counterpart of "ptrdiff_t"
/// integer type. The standard (C11 7.21.6.1p7) refers to this type
/// in the definition of %tu format specifier.
QualType getUnsignedPointerDiffType() const;

/// Return the unique type for "pid_t" defined in
/// <sys/types.h>. We need this to compute the correct type for vfork().
QualType getProcessIDType() const;
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/AST/FormatString.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#ifndef LLVM_CLANG_AST_FORMATSTRING_H
#define LLVM_CLANG_AST_FORMATSTRING_H

#include "clang/AST/ASTContext.h"
#include "clang/AST/CanonicalType.h"
#include <optional>

Expand Down Expand Up @@ -489,7 +490,8 @@ class FormatSpecifier {

/// For a TypedefType QT, if it is a named integer type such as size_t,
/// assign the appropriate value to LM and return true.
static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
static bool namedTypeToLengthModifier(ASTContext &Ctx, QualType QT,
LengthModifier &LM);
};

} // end analyze_format_string namespace
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -1210,6 +1210,8 @@ DEF_TRAVERSE_TYPE(BitIntType, {})
DEF_TRAVERSE_TYPE(DependentBitIntType,
{ TRY_TO(TraverseStmt(T->getNumBitsExpr())); })

DEF_TRAVERSE_TYPE(PredefinedSugarType, {})

#undef DEF_TRAVERSE_TYPE

// ----------------- TypeLoc traversal -----------------
Expand Down Expand Up @@ -1526,6 +1528,8 @@ DEF_TRAVERSE_TYPELOC(DependentBitIntType, {
TRY_TO(TraverseStmt(TL.getTypePtr()->getNumBitsExpr()));
})

DEF_TRAVERSE_TYPELOC(PredefinedSugarType, {})

#undef DEF_TRAVERSE_TYPELOC

// ----------------- Decl traversal -----------------
Expand Down
35 changes: 35 additions & 0 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -8054,6 +8054,41 @@ class DependentBitIntType final : public Type, public llvm::FoldingSetNode {
}
};

class PredefinedSugarType final : public Type {
public:
enum Kind { SizeT, SignedSizeT, PtrdiffT };
friend class ASTContext;

private:
Kind K;
QualType Underlying;
PredefinedSugarType(Kind KD, QualType UnderlyingType)
: Type(PredefinedSugar, UnderlyingType->getCanonicalTypeInternal(),
TypeDependence::None),
K(KD), Underlying(UnderlyingType) {}

public:
bool isSugared() const { return true; }
QualType desugar() const { return Underlying; }
Kind getKind() const { return K; }

StringRef getName() const {
switch (K) {
case SizeT:
return "__size_t";
case SignedSizeT:
return "__signed_size_t";
case PtrdiffT:
return "__ptrdiff_t";
}
llvm_unreachable("");
}

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

/// A qualifier set is used to build a set of qualifiers.
class QualifierCollector : public Qualifiers {
public:
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/TypeLoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -2767,6 +2767,10 @@ class DependentBitIntTypeLoc final
: public InheritingConcreteTypeLoc<TypeSpecTypeLoc, DependentBitIntTypeLoc,
DependentBitIntType> {};

class PredefinedSugarTypeLoc final
: public InheritingConcreteTypeLoc<TypeSpecTypeLoc, PredefinedSugarTypeLoc,
PredefinedSugarType> {};
Comment on lines +2770 to +2772
Copy link
Contributor

@mizvekov mizvekov Jun 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should ideally never be used in practice, as a PredefinedSugarType is never written in source code.
I wonder how hard it is to avoid it. Where is this coming up?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


class ObjCProtocolLoc {
ObjCProtocolDecl *Protocol = nullptr;
SourceLocation Loc = SourceLocation();
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/AST/TypeProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -1028,3 +1028,15 @@ let Class = DependentBitIntType in {
return ctx.getDependentBitIntType(isUnsigned, numBitsExpr);
}]>;
}

let Class = PredefinedSugarType in {
def : Property<"underlying", QualType> {
let Read = [{ node->desugar() }];
}
def : Property<"k", UInt32> {
let Read = [{ static_cast<uint32_t>(node->getKind()) }];
}
def : Creator<[{
return ctx.getPredefinedSugarType(k, underlying);
}]>;
}
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TypeNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,4 @@ def PipeType : TypeNode<Type>;
def AtomicType : TypeNode<Type>;
def BitIntType : TypeNode<Type>;
def DependentBitIntType : TypeNode<Type>, AlwaysDependent;
def PredefinedSugarType : TypeNode<Type>, NeverCanonical;
1 change: 1 addition & 0 deletions clang/include/clang/Serialization/TypeBitCodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,6 @@ TYPE_BIT_CODE(CountAttributed, COUNT_ATTRIBUTED, 57)
TYPE_BIT_CODE(ArrayParameter, ARRAY_PARAMETER, 58)
TYPE_BIT_CODE(HLSLAttributedResource, HLSLRESOURCE_ATTRIBUTED, 59)
TYPE_BIT_CODE(HLSLInlineSpirv, HLSL_INLINE_SPIRV, 60)
TYPE_BIT_CODE(PredefinedSugar, PREDEFINED_SUGAR, 61)

#undef TYPE_BIT_CODE
88 changes: 72 additions & 16 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2528,8 +2528,13 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
Align = static_cast<unsigned>(Width);
}
}

break;

case Type::PredefinedSugar:
return getTypeInfo(cast<PredefinedSugarType>(T)->desugar().getTypePtr());
break;

case Type::Pipe:
Width = Target->getPointerWidth(LangAS::opencl_global);
Align = Target->getPointerAlign(LangAS::opencl_global);
Expand Down Expand Up @@ -5148,6 +5153,14 @@ QualType ASTContext::getDependentBitIntType(bool IsUnsigned,
return QualType(New, 0);
}

QualType ASTContext::getPredefinedSugarType(uint32_t KD,
QualType UnderlyingType) const {
auto *New = new (*this, alignof(PredefinedSugarType)) PredefinedSugarType(
static_cast<PredefinedSugarType::Kind>(KD), UnderlyingType);
Types.push_back(New);
return QualType(New, 0);
}

#ifndef NDEBUG
static bool NeedsInjectedClassNameType(const RecordDecl *D) {
if (!isa<CXXRecordDecl>(D)) return false;
Expand Down Expand Up @@ -6726,17 +6739,70 @@ QualType ASTContext::getTagDeclType(const TagDecl *Decl) const {
return getTypeDeclType(const_cast<TagDecl*>(Decl));
}

// Using PredefinedSugarType makes size_t, signed size_t, and ptrdiff_t behave
// as named sugar types rather than built-in types, enabling better hints and
// diagnostics. In C and C++, expressions of type size_t can be obtained via the
// sizeof operator, expressions of type ptrdiff_t via pointer subtraction, and
// expressions of type signed size_t via the z literal suffix (since C++23).
// However, no core language mechanism directly produces an expression of type
// unsigned ptrdiff_t. The unsigned ptrdiff_t type is solely required by format
// specifiers for printf and scanf. Consequently, no expression's type needs to
// be displayed as unsigned ptrdiff_t. Verification of whether a type is
// unsigned ptrdiff_t is also unnecessary, as no corresponding typedefs exist.
// Therefore, unsigned ptrdiff_t does not need to do that.

/// getSizeType - Return the unique type for "size_t" (C99 7.17), the result
/// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and
/// needs to agree with the definition in <stddef.h>.
CanQualType ASTContext::getSizeType() const {
QualType ASTContext::getSizeType() const {
if (SizeType.isNull()) {
if (!getLangOpts().HLSL)
SizeType =
getPredefinedSugarType(PredefinedSugarType::Kind::SizeT,
getFromTargetType(Target->getSizeType()));
else
SizeType = getFromTargetType(Target->getSizeType());
}
return SizeType;
}

CanQualType ASTContext::getCanonicalSizeType() const {
return getFromTargetType(Target->getSizeType());
}

/// Return the unique signed counterpart of the integer type
/// corresponding to size_t.
CanQualType ASTContext::getSignedSizeType() const {
return getFromTargetType(Target->getSignedSizeType());
QualType ASTContext::getSignedSizeType() const {
if (SignedSizeType.isNull()) {
if (!getLangOpts().HLSL)
SignedSizeType = getPredefinedSugarType(
PredefinedSugarType::Kind::SignedSizeT,
getFromTargetType(Target->getSignedSizeType()));
else
SignedSizeType = getFromTargetType(Target->getSignedSizeType());
}
return SignedSizeType;
}

/// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17)
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType ASTContext::getPointerDiffType() const {
if (PtrdiffType.isNull()) {
if (!getLangOpts().HLSL)
PtrdiffType = getPredefinedSugarType(
PredefinedSugarType::Kind::PtrdiffT,
getFromTargetType(Target->getPtrDiffType(LangAS::Default)));
else
PtrdiffType = getFromTargetType(Target->getPtrDiffType(LangAS::Default));
}
return PtrdiffType;
}

/// Return the unique unsigned counterpart of "ptrdiff_t"
/// integer type. The standard (C11 7.21.6.1p7) refers to this type
/// in the definition of %tu format specifier.
QualType ASTContext::getUnsignedPointerDiffType() const {
return getFromTargetType(Target->getUnsignedPtrDiffType(LangAS::Default));
}

/// getIntMaxType - Return the unique type for "intmax_t" (C99 7.18.1.5).
Expand Down Expand Up @@ -6771,19 +6837,6 @@ QualType ASTContext::getUIntPtrType() const {
return getCorrespondingUnsignedType(getIntPtrType());
}

/// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17)
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType ASTContext::getPointerDiffType() const {
return getFromTargetType(Target->getPtrDiffType(LangAS::Default));
}

/// Return the unique unsigned counterpart of "ptrdiff_t"
/// integer type. The standard (C11 7.21.6.1p7) refers to this type
/// in the definition of %tu format specifier.
QualType ASTContext::getUnsignedPointerDiffType() const {
return getFromTargetType(Target->getUnsignedPtrDiffType(LangAS::Default));
}

/// Return the unique type for "pid_t" defined in
/// <sys/types.h>. We need this to compute the correct type for vfork().
QualType ASTContext::getProcessIDType() const {
Expand Down Expand Up @@ -14536,6 +14589,9 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
DX->isCountInBytes(), DX->isOrNull(),
CDX);
}
case Type::PredefinedSugar: {
return QualType();
}
}
llvm_unreachable("Unhandled Type Class");
}
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1894,6 +1894,12 @@ ExpectedType clang::ASTNodeImporter::VisitDependentBitIntType(
*ToNumBitsExprOrErr);
}

ExpectedType clang::ASTNodeImporter::VisitPredefinedSugarType(
const clang::PredefinedSugarType *T) {
return Importer.getToContext().getPredefinedSugarType(T->getKind(),
T->desugar());
}

ExpectedType clang::ASTNodeImporter::VisitDependentSizedMatrixType(
const clang::DependentSizedMatrixType *T) {
Error Err = Error::success();
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/AST/ASTStructuralEquivalence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1480,6 +1480,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
}
case Type::PredefinedSugar: {
const auto *TP1 = cast<PredefinedSugarType>(T1);
const auto *TP2 = cast<PredefinedSugarType>(T2);

if (TP1->getKind() != TP2->getKind())
return false;
break;
}
} // end switch

return true;
Expand Down
Loading
Loading