================
@@ -2457,9 +2457,167 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II,
QualType Type,
return New;
}
+/// Return true if the builtin type descriptor string \p Str contains a struct
+/// tag ('r<len><name>') or typedef ('t<len><name>') that must be looked up in
+/// the translation unit.
+static bool hasTargetDependentBuiltinType(const char *Str) {
+ for (const char *P = Str; *P; ++P) {
+ if (*P == 'Q' && P[1]) {
+ ++P;
+ continue;
+ }
+ if (*P == 'r' || *P == 't') {
+ char *End;
+ (void)strtoul(P + 1, &End, 10);
+ if (End != P + 1)
+ return true;
+ }
+ }
+ return false;
+}
+
+/// Decode a single return or parameter type from \p TypeStr into \p BuiltinTy.
+/// Sets \p IsTargetTypedef if the descriptor is a typedef ('t<len><name>' or
+/// 'z' for size_t) whose underlying integer type may vary across targets.
+///
+/// If a 't<len><name>' typedef has not been declared in the translation unit
+/// (e.g., when a translation unit or non-POSIX header like Winsock declares
+/// `int recv(...)` or `int recvfrom(..., int *fromlen)` without defining
+/// `ssize_t` or `socklen_t`), falls back to `int` and applies any trailing
+/// pointer/reference/qualifier modifiers so integer compatibility checks still
+/// succeed.
+static bool decodeNextBuiltinType(ASTContext &Context, const char *&TypeStr,
+ QualType &BuiltinTy, bool &IsTargetTypedef) {
+ IsTargetTypedef = (*TypeStr == 't' || *TypeStr == 'z');
+
+ bool RequireICE = false;
+ ASTContext::GetBuiltinTypeError Error = ASTContext::GE_None;
+ BuiltinTy = Context.DecodeTypeStr(TypeStr, Context, Error, RequireICE,
+ /*AllowTypeModifiers=*/true);
+ if (Error == ASTContext::GE_None)
+ return true;
+ if (!IsTargetTypedef || Error != ASTContext::GE_Missing_type)
+ return false;
+
+ // The 't<len><name>' typedef was not declared in the translation unit.
+ // Substitute `int` as a placeholder integer base type and consume any
+ // trailing pointer/reference/qualifier modifiers on this descriptor.
+ BuiltinTy = Context.IntTy;
+ while (*TypeStr) {
+ char C = *TypeStr;
+ if (C == '*' || C == '&') {
+ BuiltinTy = (C == '*') ? Context.getPointerType(BuiltinTy)
+ : Context.getLValueReferenceType(BuiltinTy);
+ ++TypeStr;
+ char *End;
+ (void)strtoul(TypeStr, &End, 10);
+ TypeStr = End;
+ } else if (C == 'C' || C == 'D' || C == 'R') {
+ ++TypeStr;
+ } else {
+ break;
+ }
+ }
+ return true;
+}
+
+/// Return true if a declared parameter or return type \p DeclTy is compatible
+/// with the expected builtin type \p BuiltinTy, accounting for platform
+/// variations in integer typedefs, transparent_union pointer wrappers, and
+/// char*/void* buffer pointers.
+static bool isCompatibleBuiltinParamOrReturnType(ASTContext &Context,
+ QualType DeclTy,
+ QualType BuiltinTy,
+ bool IsTargetTypedef) {
+ if (Context.hasSameUnqualifiedType(DeclTy, BuiltinTy))
+ return true;
+
+ // Target-dependent typedefs (e.g. mode_t, ssize_t, size_t, nfds_t, off_t)
+ // may vary in integer rank or signedness across targets and headers (e.g.
+ // Winsock's recv uses int instead of size_t/ssize_t).
+ if (IsTargetTypedef && DeclTy->isIntegerType() && BuiltinTy->isIntegerType())
+ return true;
+
+ // Allow transparent_union wrappers (such as glibc's __SOCKADDR_ARG for
+ // struct sockaddr * in recvfrom) when the builtin expects a pointer.
+ if (BuiltinTy->isPointerType()) {
+ if (const auto *RT = DeclTy->getAs<RecordType>())
+ if (RT->getDecl()->hasAttr<TransparentUnionAttr>())
+ return true;
+ }
----------------
nickdesaulniers wrote:
Back in my day, we just cast everything to `void*` (_and we liked it_)!
Thanks for explanation (makes sense), and triple checking this. Will update
this PR to incorporate that later.
https://github.com/llvm/llvm-project/pull/231696
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits