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 4 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
32 changes: 21 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 @@ -1952,6 +1953,13 @@ 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). These variables store the typedefs generated in the AST,
// not the typedefs provided in the header files.
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 +1969,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 +2025,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
69 changes: 53 additions & 16 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6726,17 +6726,67 @@ QualType ASTContext::getTagDeclType(const TagDecl *Decl) const {
return getTypeDeclType(const_cast<TagDecl*>(Decl));
}

// Inject __size_t, __signed_size_t, and __ptrdiff_t to provide portable 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, injecting a typedef for signed ptrdiff_t is not required.

/// 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 (auto const &LO = getLangOpts(); !LO.HLSL && (LO.C99 || LO.CPlusPlus))
SizeType = getTypedefType(buildImplicitTypedef(
getFromTargetType(Target->getSizeType()), "__size_t"));
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 (auto const &LO = getLangOpts(); !LO.HLSL && (LO.C99 || LO.CPlusPlus))
SignedSizeType = getTypedefType(buildImplicitTypedef(
getFromTargetType(Target->getSignedSizeType()), "__signed_size_t"));
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 (auto const &LO = getLangOpts(); !LO.HLSL && (LO.C99 || LO.CPlusPlus))
PtrdiffType = getTypedefType(buildImplicitTypedef(
getFromTargetType(Target->getPtrDiffType(LangAS::Default)),
"__ptrdiff_t"));
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));
}
Comment on lines +6856 to 6858
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm confused, isn't this supposed to return the sugared ptrdiff type?


/// getIntMaxType - Return the unique type for "intmax_t" (C99 7.18.1.5).
Expand Down Expand Up @@ -6771,19 +6821,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
108 changes: 87 additions & 21 deletions clang/lib/AST/FormatString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//

#include "clang/AST/FormatString.h"
#include "FormatStringParsing.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetInfo.h"
Expand Down Expand Up @@ -320,6 +321,69 @@ bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(
// Methods on ArgType.
//===----------------------------------------------------------------------===//

static bool namedTypeToLengthModifierKind(QualType QT,
LengthModifier::Kind &K) {
for (/**/; const auto *TT = QT->getAs<TypedefType>();
QT = TT->getDecl()->getUnderlyingType()) {
StringRef Name = TT->getDecl()->getIdentifier()->getName();
if (Name == "size_t" || Name == "__size_t") {
K = LengthModifier::AsSizeT;
return true;
} else if (Name == "__signed_size_t" ||
Name == "ssize_t" /*Not C99, but common in Unix.*/) {
K = LengthModifier::AsSizeT;
return true;
} else if (Name == "ptrdiff_t" || Name == "__ptrdiff_t") {
K = LengthModifier::AsPtrDiff;
return true;
} else if (Name == "intmax_t") {
K = LengthModifier::AsIntMax;
return true;
} else if (Name == "uintmax_t") {
K = LengthModifier::AsIntMax;
return true;
}
}
return false;
}

// Check whether T and E are compatible size_t/ptrdiff_t typedefs. E must be
// consistent with LE.
// T is the type of the actual expression in the code to be checked, and E is
// the expected type parsed from the format string.
static clang::analyze_format_string::ArgType::MatchKind
matchesSizeTPtrdiffT(ASTContext &C, QualType T, QualType E,
LengthModifier::Kind LE) {
using Kind = LengthModifier::Kind;
using MatchKind = clang::analyze_format_string::ArgType::MatchKind;
assert(LE == Kind::AsPtrDiff || LE == Kind::AsSizeT);

if (!T->isIntegerType())
return MatchKind::NoMatch;

if (C.getCorrespondingSignedType(T.getCanonicalType()) !=
C.getCorrespondingSignedType(E.getCanonicalType()))
return MatchKind::NoMatch;

// signed size_t and unsigned ptrdiff_t does not have typedefs in C and C++.
if (LE == Kind::AsSizeT && E->isSignedIntegerType())
return T->isSignedIntegerType() ? MatchKind::Match
: MatchKind::NoMatchSignedness;

if (LE == LengthModifier::Kind::AsPtrDiff && E->isUnsignedIntegerType())
return T->isUnsignedIntegerType() ? MatchKind::Match
: MatchKind::NoMatchSignedness;

if (Kind Actual = Kind::None; namedTypeToLengthModifierKind(T, Actual)) {
if (Actual == LE)
return MatchKind::Match;
else if (Actual == Kind::AsPtrDiff || Actual == Kind::AsSizeT)
return MatchKind::NoMatchSignedness;
}

return MatchKind::NoMatch;
}

clang::analyze_format_string::ArgType::MatchKind
ArgType::matchesType(ASTContext &C, QualType argTy) const {
// When using the format attribute in C++, you can receive a function or an
Expand Down Expand Up @@ -394,6 +458,13 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
}

case SpecificTy: {
if (TK != TypeKind::DontCare) {
return matchesSizeTPtrdiffT(C, argTy, T,
TK == TypeKind::SizeT
? LengthModifier::Kind::AsSizeT
: LengthModifier::AsPtrDiff);
}

if (const EnumType *ETy = argTy->getAs<EnumType>()) {
// If the enum is incomplete we know nothing about the underlying type.
// Assume that it's 'int'. Do not use the underlying type for a scoped
Expand Down Expand Up @@ -653,6 +724,18 @@ ArgType::matchesArgType(ASTContext &C, const ArgType &Other) const {

if (Left.K == AK::SpecificTy) {
if (Right.K == AK::SpecificTy) {
if (Left.TK != TypeKind::DontCare) {
return matchesSizeTPtrdiffT(C, Right.T, Left.T,
Left.TK == TypeKind::SizeT
? LengthModifier::Kind::AsSizeT
: LengthModifier::AsPtrDiff);
} else if (Right.TK != TypeKind::DontCare) {
return matchesSizeTPtrdiffT(C, Left.T, Right.T,
Right.TK == TypeKind::SizeT
? LengthModifier::Kind::AsSizeT
: LengthModifier::AsPtrDiff);
}

auto Canon1 = C.getCanonicalType(Left.T);
auto Canon2 = C.getCanonicalType(Right.T);
if (Canon1 == Canon2)
Expand Down Expand Up @@ -1200,27 +1283,10 @@ FormatSpecifier::getCorrectedLengthModifier() const {

bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
LengthModifier &LM) {
for (/**/; const auto *TT = QT->getAs<TypedefType>();
QT = TT->getDecl()->getUnderlyingType()) {
const TypedefNameDecl *Typedef = TT->getDecl();
const IdentifierInfo *Identifier = Typedef->getIdentifier();
if (Identifier->getName() == "size_t") {
LM.setKind(LengthModifier::AsSizeT);
return true;
} else if (Identifier->getName() == "ssize_t") {
// Not C99, but common in Unix.
LM.setKind(LengthModifier::AsSizeT);
return true;
} else if (Identifier->getName() == "intmax_t") {
LM.setKind(LengthModifier::AsIntMax);
return true;
} else if (Identifier->getName() == "uintmax_t") {
LM.setKind(LengthModifier::AsIntMax);
return true;
} else if (Identifier->getName() == "ptrdiff_t") {
LM.setKind(LengthModifier::AsPtrDiff);
return true;
}
if (LengthModifier::Kind Out = LengthModifier::Kind::None;
namedTypeToLengthModifierKind(QT, Out)) {
LM.setKind(Out);
return true;
}
return false;
}
9 changes: 6 additions & 3 deletions clang/lib/AST/PrintfFormatString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,8 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
case LengthModifier::AsIntMax:
return ArgType(Ctx.getIntMaxType(), "intmax_t");
case LengthModifier::AsSizeT:
return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
return ArgType::makeSizeT(
ArgType(Ctx.getSignedSizeType(), "signed size_t"));
case LengthModifier::AsInt3264:
return Ctx.getTargetInfo().getTriple().isArch64Bit()
? ArgType(Ctx.LongLongTy, "__int64")
Expand Down Expand Up @@ -626,9 +627,11 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
case LengthModifier::AsIntMax:
return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
case LengthModifier::AsSizeT:
return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
return ArgType::PtrTo(ArgType::makeSizeT(
ArgType(Ctx.getSignedSizeType(), "signed size_t")));
case LengthModifier::AsPtrDiff:
return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
return ArgType::PtrTo(ArgType::makePtrdiffT(
ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")));
case LengthModifier::AsLongDouble:
return ArgType(); // FIXME: Is this a known extension?
case LengthModifier::AsAllocate:
Expand Down
19 changes: 12 additions & 7 deletions clang/lib/AST/ScanfFormatString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,11 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsIntMax:
return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
case LengthModifier::AsSizeT:
return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
return ArgType::PtrTo(ArgType::makeSizeT(
ArgType(Ctx.getSignedSizeType(), "signed size_t")));
case LengthModifier::AsPtrDiff:
return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
return ArgType::PtrTo(ArgType::makePtrdiffT(
ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")));
case LengthModifier::AsLongDouble:
// GNU extension.
return ArgType::PtrTo(Ctx.LongLongTy);
Expand Down Expand Up @@ -292,10 +294,11 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsIntMax:
return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));
case LengthModifier::AsSizeT:
return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
case LengthModifier::AsPtrDiff:
return ArgType::PtrTo(
ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t")));
case LengthModifier::AsPtrDiff:
return ArgType::PtrTo(ArgType::makePtrdiffT(
ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t")));
case LengthModifier::AsLongDouble:
// GNU extension.
return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
Expand Down Expand Up @@ -390,9 +393,11 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsIntMax:
return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
case LengthModifier::AsSizeT:
return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
return ArgType::PtrTo(ArgType::makeSizeT(
ArgType(Ctx.getSignedSizeType(), "signed size_t")));
case LengthModifier::AsPtrDiff:
return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
return ArgType::PtrTo(ArgType::makePtrdiffT(
ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")));
case LengthModifier::AsLongDouble:
return ArgType(); // FIXME: Is this a known extension?
case LengthModifier::AsAllocate:
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,8 @@ static void appendParameterTypes(
for (unsigned I = 0, E = FPT->getNumParams(); I != E; ++I) {
prefix.push_back(FPT->getParamType(I));
if (ExtInfos[I].hasPassObjectSize())
prefix.push_back(CGT.getContext().getSizeType());
prefix.push_back(
CGT.getContext().getCanonicalSizeType());
}

addExtParameterInfosForCall(paramInfos, FPT.getTypePtr(), PrefixSize,
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/CGCoroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1002,14 +1002,14 @@ RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E,
}
case llvm::Intrinsic::coro_size: {
auto &Context = getContext();
CanQualType SizeTy = Context.getSizeType();
CanQualType SizeTy = Context.getCanonicalSizeType();
llvm::IntegerType *T = Builder.getIntNTy(Context.getTypeSize(SizeTy));
llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::coro_size, T);
return RValue::get(Builder.CreateCall(F));
}
case llvm::Intrinsic::coro_align: {
auto &Context = getContext();
CanQualType SizeTy = Context.getSizeType();
CanQualType SizeTy = Context.getCanonicalSizeType();
llvm::IntegerType *T = Builder.getIntNTy(Context.getTypeSize(SizeTy));
llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::coro_align, T);
return RValue::get(Builder.CreateCall(F));
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGObjCMac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ class ObjCCommonTypesHelper {
SmallVector<CanQualType, 5> Params;
Params.push_back(Ctx.VoidPtrTy);
Params.push_back(Ctx.VoidPtrTy);
Params.push_back(Ctx.getSizeType());
Params.push_back(Ctx.getCanonicalSizeType());
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy = Types.GetFunctionType(
Expand Down
Loading