diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h --- a/clang/include/clang/AST/CanonicalType.h +++ b/clang/include/clang/AST/CanonicalType.h @@ -264,6 +264,8 @@ // Type predicates LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjectType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSizelessType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSizelessBuiltinType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteOrObjectType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariablyModifiedType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegerType) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1926,6 +1926,15 @@ /// or QualType::getSingleStepDesugaredType(const ASTContext&). QualType getLocallyUnqualifiedSingleStepDesugaredType() const; + /// As an extension, we classify types as one of "sized" or "sizeless"; + /// every type is one or the other. Standard types are all sized; + /// sizeless types are purely an extension. + /// + /// Sizeless types contain data with no specified size, alignment, + /// or layout. + bool isSizelessType() const; + bool isSizelessBuiltinType() const; + /// Types are partitioned into 3 broad categories (C99 6.2.5p1): /// object types, function types, and incomplete types. diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2182,6 +2182,22 @@ } } +bool Type::isSizelessBuiltinType() const { + if (const BuiltinType *BT = getAs()) { + switch (BT->getKind()) { + // SVE Types +#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#include "clang/Basic/AArch64SVEACLETypes.def" + return true; + default: + return false; + } + } + return false; +} + +bool Type::isSizelessType() const { return isSizelessBuiltinType(); } + bool QualType::isPODType(const ASTContext &Context) const { // C++11 has a more relaxed definition of POD. if (Context.getLangOpts().CPlusPlus11) diff --git a/clang/unittests/AST/CMakeLists.txt b/clang/unittests/AST/CMakeLists.txt --- a/clang/unittests/AST/CMakeLists.txt +++ b/clang/unittests/AST/CMakeLists.txt @@ -28,6 +28,7 @@ Language.cpp NamedDeclPrinterTest.cpp RecursiveASTVisitorTest.cpp + SizelessTypesTest.cpp SourceLocationTest.cpp StmtPrinterTest.cpp StructuralEquivalenceTest.cpp diff --git a/clang/unittests/AST/SizelessTypesTest.cpp b/clang/unittests/AST/SizelessTypesTest.cpp new file mode 100644 --- /dev/null +++ b/clang/unittests/AST/SizelessTypesTest.cpp @@ -0,0 +1,82 @@ +//===- unittests/AST/SizelessTypesTest.cpp --- Sizeless type tests --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains tests for clang::Type queries related to sizeless types. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" + +using namespace clang; + +struct SizelessTypeTester : public ::testing::Test { + // Declare an incomplete structure type. + std::unique_ptr AST = tooling::buildASTFromCodeWithArgs( + "struct foo;", {"-target", "aarch64-linux-gnu"}); + ASTContext &Ctx = AST->getASTContext(); + TranslationUnitDecl &TU = *Ctx.getTranslationUnitDecl(); + TypeDecl *Foo = cast(TU.lookup(&Ctx.Idents.get("foo")).front()); + const Type *FooTy = Foo->getTypeForDecl(); +}; + +TEST_F(SizelessTypeTester, TestSizelessBuiltin) { + ASSERT_TRUE(Ctx.SveInt8Ty->isSizelessBuiltinType()); + ASSERT_TRUE(Ctx.SveInt16Ty->isSizelessBuiltinType()); + ASSERT_TRUE(Ctx.SveInt32Ty->isSizelessBuiltinType()); + ASSERT_TRUE(Ctx.SveInt64Ty->isSizelessBuiltinType()); + + ASSERT_TRUE(Ctx.SveUint8Ty->isSizelessBuiltinType()); + ASSERT_TRUE(Ctx.SveUint16Ty->isSizelessBuiltinType()); + ASSERT_TRUE(Ctx.SveUint32Ty->isSizelessBuiltinType()); + ASSERT_TRUE(Ctx.SveUint64Ty->isSizelessBuiltinType()); + + ASSERT_TRUE(Ctx.SveFloat16Ty->isSizelessBuiltinType()); + ASSERT_TRUE(Ctx.SveFloat32Ty->isSizelessBuiltinType()); + ASSERT_TRUE(Ctx.SveFloat64Ty->isSizelessBuiltinType()); + + ASSERT_TRUE(Ctx.SveBoolTy->isSizelessBuiltinType()); + + ASSERT_FALSE(Ctx.VoidTy->isSizelessBuiltinType()); + ASSERT_FALSE(Ctx.PseudoObjectTy->isSizelessBuiltinType()); + ASSERT_FALSE(FooTy->isSizelessBuiltinType()); + + ASSERT_FALSE(Ctx.getPointerType(Ctx.SveBoolTy)->isSizelessBuiltinType()); + ASSERT_FALSE( + Ctx.getLValueReferenceType(Ctx.SveBoolTy)->isSizelessBuiltinType()); + ASSERT_FALSE( + Ctx.getRValueReferenceType(Ctx.SveBoolTy)->isSizelessBuiltinType()); +} + +TEST_F(SizelessTypeTester, TestSizeless) { + ASSERT_TRUE(Ctx.SveInt8Ty->isSizelessType()); + ASSERT_TRUE(Ctx.SveInt16Ty->isSizelessType()); + ASSERT_TRUE(Ctx.SveInt32Ty->isSizelessType()); + ASSERT_TRUE(Ctx.SveInt64Ty->isSizelessType()); + + ASSERT_TRUE(Ctx.SveUint8Ty->isSizelessType()); + ASSERT_TRUE(Ctx.SveUint16Ty->isSizelessType()); + ASSERT_TRUE(Ctx.SveUint32Ty->isSizelessType()); + ASSERT_TRUE(Ctx.SveUint64Ty->isSizelessType()); + + ASSERT_TRUE(Ctx.SveFloat16Ty->isSizelessType()); + ASSERT_TRUE(Ctx.SveFloat32Ty->isSizelessType()); + ASSERT_TRUE(Ctx.SveFloat64Ty->isSizelessType()); + + ASSERT_TRUE(Ctx.SveBoolTy->isSizelessType()); + + ASSERT_FALSE(Ctx.VoidTy->isSizelessType()); + ASSERT_FALSE(Ctx.PseudoObjectTy->isSizelessType()); + ASSERT_FALSE(FooTy->isSizelessType()); + + ASSERT_FALSE(Ctx.getPointerType(Ctx.SveBoolTy)->isSizelessType()); + ASSERT_FALSE(Ctx.getLValueReferenceType(Ctx.SveBoolTy)->isSizelessType()); + ASSERT_FALSE(Ctx.getRValueReferenceType(Ctx.SveBoolTy)->isSizelessType()); +}