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,10 @@ // Type predicates LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjectType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDefiniteType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIndefiniteType) + 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 @@ -1908,6 +1908,29 @@ /// 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. They are always incomplete. + bool isSizelessType() const; + bool isSizelessBuiltinType() const; + + /// As an extension, we classify types as one of "definite" or "indefinite"; + /// every type is one or the other. Definite types provide enough + /// information to construct new objects of that type while indefinite + /// types do not. A type is indefinite iff the type is both "sized" + /// and incomplete according to the standard definition. + /// + /// If Def is non-null, and the type refers to some kind of declaration + /// that can be completed (such as a C struct, C++ class, or Objective-C + /// class), Def will be set to the declaration. + bool isIndefiniteType(NamedDecl **Def = nullptr) const; + bool isDefiniteType(NamedDecl **Def = nullptr) const { + return !isIndefiniteType(Def); + } + /// Types are partitioned into 3 broad categories (C99 6.2.5p1): /// object types, function types, and incomplete types. @@ -1919,7 +1942,9 @@ /// Def If non-null, and the type refers to some kind of declaration /// that can be completed (such as a C struct, C++ class, or Objective-C /// class), will be set to the declaration. - bool isIncompleteType(NamedDecl **Def = nullptr) const; + bool isIncompleteType(NamedDecl **Def = nullptr) const { + return isIndefiniteType(Def); + } /// Return true if this is an incomplete or object /// type, in other words, not a function type. 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 @@ -2109,10 +2109,10 @@ return !isa(CanonicalType); } -/// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1) -/// - a type that can describe objects, but which lacks information needed to -/// determine its size. -bool Type::isIncompleteType(NamedDecl **Def) const { +/// isIndefiniteType - Return true if this is an indefinite type - a type that +/// can describe objects, but lacks information needed to construct them. +/// For sized types, "indefinite" is equivalent to "incomplete" (C99 6.2.5p1). +bool Type::isIndefiniteType(NamedDecl **Def) const { if (Def) *Def = nullptr; @@ -2182,6 +2182,24 @@ } } +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 @@ -29,6 +29,7 @@ NamedDeclPrinterTest.cpp OMPStructuredBlockTest.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,81 @@ +//===- 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, 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()); +} + +TEST_F(SizelessTypeTester, TestIndefinite) { + ASSERT_FALSE(Ctx.SveInt8Ty->isIndefiniteType()); + ASSERT_FALSE(Ctx.SveInt16Ty->isIndefiniteType()); + ASSERT_FALSE(Ctx.SveInt32Ty->isIndefiniteType()); + ASSERT_FALSE(Ctx.SveInt64Ty->isIndefiniteType()); + + ASSERT_FALSE(Ctx.SveUint8Ty->isIndefiniteType()); + ASSERT_FALSE(Ctx.SveUint16Ty->isIndefiniteType()); + ASSERT_FALSE(Ctx.SveUint32Ty->isIndefiniteType()); + ASSERT_FALSE(Ctx.SveUint64Ty->isIndefiniteType()); + + ASSERT_FALSE(Ctx.SveFloat16Ty->isIndefiniteType()); + ASSERT_FALSE(Ctx.SveFloat32Ty->isIndefiniteType()); + ASSERT_FALSE(Ctx.SveFloat64Ty->isIndefiniteType()); + + ASSERT_FALSE(Ctx.SveBoolTy->isIndefiniteType()); + + ASSERT_TRUE(Ctx.VoidTy->isIndefiniteType()); + ASSERT_FALSE(Ctx.PseudoObjectTy->isIndefiniteType()); + ASSERT_TRUE(FooTy->isIndefiniteType()); + + ASSERT_FALSE(Ctx.getPointerType(Ctx.SveBoolTy)->isIndefiniteType()); + ASSERT_FALSE(Ctx.getLValueReferenceType(Ctx.SveBoolTy)->isIndefiniteType()); + ASSERT_FALSE(Ctx.getRValueReferenceType(Ctx.SveBoolTy)->isIndefiniteType()); +}