rsandifo-arm created this revision.
Herald added subscribers: cfe-commits, mgorny.
Herald added a project: clang.

This patch adds new type queries:

- isSizelessType
- isDefiniteType
- isIndefiniteType

following the type classification described in the comments.
The follow-on patch to support sizeless types in C and C++
has more details about the sizeless type extension.


Repository:
  rC Clang

https://reviews.llvm.org/D62961

Files:
  include/clang/AST/CanonicalType.h
  include/clang/AST/Type.h
  lib/AST/Type.cpp
  unittests/AST/CMakeLists.txt
  unittests/AST/SizelessTypesTest.cpp

Index: unittests/AST/SizelessTypesTest.cpp
===================================================================
--- /dev/null
+++ unittests/AST/SizelessTypesTest.cpp
@@ -0,0 +1,105 @@
+//===- 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<ASTUnit> AST = tooling::buildASTFromCode("struct foo;");
+  ASTContext &Ctx = AST->getASTContext();
+  TranslationUnitDecl &TU = *Ctx.getTranslationUnitDecl();
+  TypeDecl *Foo = cast<TypeDecl>(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());
+}
+
+TEST_F(SizelessTypeTester, TestIncomplete) {
+  ASSERT_TRUE(Ctx.SveInt8Ty->isIncompleteType());
+  ASSERT_TRUE(Ctx.SveInt16Ty->isIncompleteType());
+  ASSERT_TRUE(Ctx.SveInt32Ty->isIncompleteType());
+  ASSERT_TRUE(Ctx.SveInt64Ty->isIncompleteType());
+
+  ASSERT_TRUE(Ctx.SveUint8Ty->isIncompleteType());
+  ASSERT_TRUE(Ctx.SveUint16Ty->isIncompleteType());
+  ASSERT_TRUE(Ctx.SveUint32Ty->isIncompleteType());
+  ASSERT_TRUE(Ctx.SveUint64Ty->isIncompleteType());
+
+  ASSERT_TRUE(Ctx.SveFloat16Ty->isIncompleteType());
+  ASSERT_TRUE(Ctx.SveFloat32Ty->isIncompleteType());
+  ASSERT_TRUE(Ctx.SveFloat64Ty->isIncompleteType());
+
+  ASSERT_TRUE(Ctx.SveBoolTy->isIncompleteType());
+
+  ASSERT_TRUE(Ctx.VoidTy->isIncompleteType());
+  ASSERT_FALSE(Ctx.PseudoObjectTy->isIncompleteType());
+  ASSERT_TRUE(FooTy->isIncompleteType());
+
+  ASSERT_FALSE(Ctx.getPointerType(Ctx.SveBoolTy)->isIncompleteType());
+  ASSERT_FALSE(Ctx.getLValueReferenceType(Ctx.SveBoolTy)->isIncompleteType());
+  ASSERT_FALSE(Ctx.getRValueReferenceType(Ctx.SveBoolTy)->isIncompleteType());
+}
Index: unittests/AST/CMakeLists.txt
===================================================================
--- unittests/AST/CMakeLists.txt
+++ unittests/AST/CMakeLists.txt
@@ -26,6 +26,7 @@
   Language.cpp
   NamedDeclPrinterTest.cpp
   OMPStructuredBlockTest.cpp
+  SizelessTypesTest.cpp
   SourceLocationTest.cpp
   StmtPrinterTest.cpp
   StructuralEquivalenceTest.cpp
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -2056,10 +2056,10 @@
   return !isa<VariableArrayType>(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;
 
@@ -2129,6 +2129,27 @@
   }
 }
 
+bool Type::isSizelessBuiltinType() const {
+  if (const BuiltinType *BT = getAs<BuiltinType>()) {
+    switch (BT->getKind()) {
+    // SVE Types
+#define SVE_VECTOR_TYPE(Name, Id, SingletonId, ElKind, ElBits, IsSigned, IsFP)\
+    case BuiltinType::Id:
+#define SVE_PREDICATE_TYPE(Name, Id, SingletonId, ElKind) \
+    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)
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -1852,6 +1852,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.
 
@@ -1860,10 +1883,23 @@
   /// determine its size (e.g. void, or a fwd declared struct). Clients of this
   /// routine will need to determine if the size is actually required.
   ///
+  /// A type is incomplete according to our definition iff:
+  /// - it is incomplete according to the standard definition; or
+  /// - it is "sizeless"
+  ///
+  /// The intention is that the usual rules for incomplete types will
+  /// by default apply to sizeless types as well.  Specifically-chosen
+  /// rules can then be redefined in terms of "definite" and "indefinite"
+  /// if sizeless definite types are acceptable.
+  ///
   /// 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 {
+    // isIndefiniteType also sets Def to nullptr on failure, so the call
+    // to isSizelessType is safe.
+    return isIndefiniteType(Def) || isSizelessType();
+  }
 
   /// Return true if this is an incomplete or object
   /// type, in other words, not a function type.
Index: include/clang/AST/CanonicalType.h
===================================================================
--- include/clang/AST/CanonicalType.h
+++ 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)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D62961: [AST] Ad... Richard Sandiford via Phabricator via cfe-commits

Reply via email to