Skip to content

[BoundsSafety] Support __single and __unsafe_indexable in template definitions in attribute only mode#10779

Merged
delcypher merged 1 commit intoswiftlang:nextfrom
delcypher:dliew/rdar-152249884
Jun 4, 2025
Merged

[BoundsSafety] Support __single and __unsafe_indexable in template definitions in attribute only mode#10779
delcypher merged 1 commit intoswiftlang:nextfrom
delcypher:dliew/rdar-152249884

Conversation

@delcypher
Copy link
Copy Markdown

Previously code like this would fail to compile:

template <class T>
class Ref {
  public:
  T __single ptr;
};

void use() {
  Ref<int*> ok;
}

with the following error

error: '__single' attribute only applies to pointer arguments

This happens because we try to do type checking on the uninstantiated template which fails because T is a TemplateTypeParmType and not a PointerType.

In -fbounds-safety mode there's no good way to fix this because __single and __unsafe_indexable are part of the PointerType so the attribute can't be represented in the AST because there is no PointerType, only a TemplateTypeParmType.

However, in -fexperimental-bounds-safety-attributes mode __single and __unsafe_indexable are represented as type sugar (AttributedType). This means it is possible to add the AttributedType on the TemplateTypeParmType (i.e. adding sugar to the unknown template type).

This patch makes the above code compile in
-fexperimental-bounds-safety-attributes mode by

  • Removing the error diagnostic when the type being checked in HandleBoundsSafetyPointerTypeAttr(...) is a TemplateTypeParmType and we are in -fexperimental-bounds-safety-attributes mode.

  • Adding ConstructBoundsSafetyPointerType::VisitTemplateTypeParmTypeLoc so that the __single or __unsafe_indexable type sugar is applied when in -fexperimental-bounds-safety-attributes mode.

  • Teaching TreeTransform<Derived>::TransformAttributedType to check that __single and __unsafe_indexable are being applied to PointerType. This method is used by the TemplateInstantiator class which performs template instantiation.

In principle a similar approach could be used to support __null_terminated in template definitions. However, doing so would be quite complicated and should be handled separately (rdar://152451848).

rdar://152249884

@delcypher delcypher self-assigned this Jun 2, 2025
@delcypher delcypher added the clang:bounds-safety Issue relating to the experimental -fbounds-safety feature in Clang label Jun 2, 2025
@delcypher
Copy link
Copy Markdown
Author

@swift-ci test llvm

@delcypher
Copy link
Copy Markdown
Author

@rapidsna I think you may have already come to this conclusion but my experience working on this patch suggests that all of our attributes should be type sugar rather than being embedded in PointerType. Otherwise it is impossible to write the attributes in uninstantiated templates.

@delcypher
Copy link
Copy Markdown
Author

@patrykstefanski I did look at doing this for __null_terminated and I realized it is much more complicated so I punted doing it to a separate radar (rdar://152451848). The problems I noticed for __null_terminated are

  • HandlePtrTerminatedByTypeAttr assumes it can access the pointee type. That can't happen when the type is TemplateTypeParmType. We would need to refactor the sema checks into ones we can do without knowing the pointee type and ones where we need the pointee type. Then we'd need to delay the sema checks that need the pointee type (and don't have it) until we reach template instantiation.

  • HandlePtrTerminatedByTypeAttr constructs a cast expression using the pointee type. We can't do that if we don't know the pointee type. We probably need to come up with some kind of convention in the AST where at template instantiation time we insert the correct cast.

Comment thread clang/test/BoundsSafety/Sema/attributes_in_template_decls.cpp Outdated
Comment thread clang/test/BoundsSafety/AST/attributes_in_template_decls_attr_only_mode.cpp Outdated
Comment thread clang/lib/Sema/TreeTransform.h Outdated
Comment thread clang/lib/Sema/TreeTransform.h Outdated
Comment thread clang/lib/Sema/TreeTransform.h Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There may be other cases, but if the code was ever modified so that -fbounds-safety could reach here, I think implicitly single pointers would probably miss spelling

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Got it. When I made the C++ example work with full -fbounds-safety it seems we went down this path but I didn't look into why.

Comment thread clang/lib/Sema/SemaType.cpp Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why only in attribute-only mode?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Because in that mode __single and __unsafe_indexable are sugar types. In -fbounds-safety that information is embedded in PointerType instead. Given that there's no good way to make this work in -fbounds-safety right now I decided to limit this to attribute-only mode. This seems like the right call given that it's the only one that really matters right now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure we need to implement this for -fbounds-safety now, but I'm not sure that there isn't any good way to make that work.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Ok there is a way. As you outlined elsewhere we could represent __single and __unsafe_indexable as sugar types in the AST for uninstantiated templates and then at template instantiation time rewrite the AST so that the sugar is dropped and the appropriate attribute is set in the PointerType.

This doesn't seem good to me because we'd be using two different representations for "is single" in the AST which might lead to bugs. Probably more importantly, I don't think this is an important problem to solve right now.

@hnrklssn
Copy link
Copy Markdown
Member

hnrklssn commented Jun 2, 2025

@rapidsna I think you may have already come to this conclusion but my experience working on this patch suggests that all of our attributes should be type sugar rather than being embedded in PointerType. Otherwise it is impossible to write the attributes in uninstantiated templates.

What we do for __counted_by et.al. is to apply the sugar (actually an attribute in that case, but same principle) as if in attribute-only-mode when used in templated contexts, deferring the parsing until template instantiation. We could do the same thing here.

Comment thread clang/lib/Sema/TreeTransform.h Outdated
@patrykstefanski
Copy link
Copy Markdown

I think we discussed this offline. But, allowing those attributes to be only used on pointers wouldn't work? That is, T __single ptr would be an error, but T *__single ptr would be fine.

@delcypher
Copy link
Copy Markdown
Author

@patrykstefanski

I think we discussed this offline. But, allowing those attributes to be only used on pointers wouldn't work? That is, T __single ptr would be an error, but T *__single ptr would be fine.

We could do that but this problem seems simple enough to fix that I figured we should just do it.

@delcypher
Copy link
Copy Markdown
Author

@swift-ci test

@delcypher
Copy link
Copy Markdown
Author

@swift-ci test llvm

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

good shout, this here is firmly in the arcane realm

Copy link
Copy Markdown
Member

@hnrklssn hnrklssn left a comment

Choose a reason for hiding this comment

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

Thanks for the thorough testing!

@hnrklssn
Copy link
Copy Markdown
Member

hnrklssn commented Jun 4, 2025

@swift-ci please smoke test

@hnrklssn
Copy link
Copy Markdown
Member

hnrklssn commented Jun 4, 2025

@swift-ci please test

@delcypher
Copy link
Copy Markdown
Author

Swift Test for macOS failure looks unrelated.

00:05:07  In file included from /Users/ec2-user/jenkins/workspace/apple-llvm-project-pr-macos/branch-next/llvm-project/libcxxabi/src/cxa_demangle.cpp:17:
00:05:07  In file included from /Users/ec2-user/jenkins/workspace/apple-llvm-project-pr-macos/branch-next/llvm-project/libcxxabi/src/demangle/ItaniumDemangle.h:20:
00:05:07  In file included from /Users/ec2-user/jenkins/workspace/apple-llvm-project-pr-macos/branch-next/llvm-project/libcxxabi/src/demangle/StringViewExtras.h:20:
00:05:07  In file included from /Users/ec2-user/jenkins/workspace/apple-llvm-project-pr-macos/branch-next/build/buildbot_incremental/libcxx-macosx-x86_64/include/c++/v1/string_view:211:
00:05:07  In file included from /Users/ec2-user/jenkins/workspace/apple-llvm-project-pr-macos/branch-next/build/buildbot_incremental/libcxx-macosx-x86_64/include/c++/v1/__algorithm/min.h:14:
00:05:07  In file included from /Users/ec2-user/jenkins/workspace/apple-llvm-project-pr-macos/branch-next/build/buildbot_incremental/libcxx-macosx-x86_64/include/c++/v1/__algorithm/min_element.h:16:
00:05:07  In file included from /Users/ec2-user/jenkins/workspace/apple-llvm-project-pr-macos/branch-next/build/buildbot_incremental/libcxx-macosx-x86_64/include/c++/v1/__iterator/iterator_traits.h:14:
00:05:07  In file included from /Users/ec2-user/jenkins/workspace/apple-llvm-project-pr-macos/branch-next/build/buildbot_incremental/libcxx-macosx-x86_64/include/c++/v1/__concepts/constructible.h:12:
00:05:07  In file included from /Users/ec2-user/jenkins/workspace/apple-llvm-project-pr-macos/branch-next/build/buildbot_incremental/libcxx-macosx-x86_64/include/c++/v1/__concepts/convertible_to.h:13:
00:05:07  /Users/ec2-user/jenkins/workspace/apple-llvm-project-pr-macos/branch-next/build/buildbot_incremental/libcxx-macosx-x86_64/include/c++/v1/__type_traits/is_convertible.h:32:99: error: '_Tp' does not refer to a value
00:05:07     32 | struct _LIBCPP_NO_SPECIALIZATIONS is_nothrow_convertible : bool_constant<__is_nothrow_convertible(_Tp, _Up)> {};
00:05:07        |                                                                                                   ^
00:05:07  /Users/ec2-user/jenkins/workspace/apple-llvm-project-pr-macos/branch-next/build/buildbot_incremental/libcxx-macosx-x86_64/include/c++/v1/__type_traits/is_convertible.h:31:17: note: declared here
00:05:07     31 | template <class _Tp, class _Up>
00:05:07        |                 ^

@delcypher
Copy link
Copy Markdown
Author

I'm going to squash and merge.

…finitions in attribute only mode

Previously code like this would fail to compile:

```
template <class T>
class Ref {
  public:
  T __single ptr;
};

void use() {
  Ref<int*> ok;
}
```

with the following error

```
error: '__single' attribute only applies to pointer arguments
```

This happens because we try to do type checking on the uninstantiated
template which fails because `T` is a `TemplateTypeParmType` and not a
`PointerType`.

In `-fbounds-safety` mode there's no good way to fix this because
`__single` and `__unsafe_indexable` are part of the `PointerType` so the
attribute can't be represented in the AST because there is no
`PointerType`, only a `TemplateTypeParmType`.

However, in `-fexperimental-bounds-safety-attributes` mode `__single`
and `__unsafe_indexable` are represented as type sugar (`AttributedType`).
This means it is possible to add the AttributedType on the
`TemplateTypeParmType` (i.e. adding sugar to the unknown template type).

This patch makes the above code compile in
`-fexperimental-bounds-safety-attributes` mode by

* Removing the error diagnostic when the type being checked in
  `HandleBoundsSafetyPointerTypeAttr(...)` is a `TemplateTypeParmType`
  and we are in `-fexperimental-bounds-safety-attributes` mode.

* Adding `ConstructBoundsSafetyPointerType::VisitTemplateTypeParmTypeLoc`
  so that the `__single` or `__unsafe_indexable` type sugar is applied
  when in `-fexperimental-bounds-safety-attributes` mode.

* Teaching `TreeTransform<Derived>::TransformAttributedType` to check that
  `__single` and `__unsafe_indexable` are being applied to `PointerType`.
  This method is used by the `TemplateInstantiator` class which performs
  template instantiation.

In principle a similar approach could be used to support
`__null_terminated` in template definitions. However, doing so would be
quite complicated and should be handled separately (rdar://152451848).

rdar://152249884
@delcypher delcypher force-pushed the dliew/rdar-152249884 branch from 633c528 to 1f11772 Compare June 4, 2025 17:21
@delcypher delcypher merged commit 0b5168f into swiftlang:next Jun 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:bounds-safety Issue relating to the experimental -fbounds-safety feature in Clang

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants