Skip to content

[clang/AST] Make it possible to use SwiftAttr in type context #108631

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,19 @@ Removed Compiler Flags
Attribute Changes in Clang
--------------------------

- The ``swift_attr`` can now be applied to types. To make it possible to use imported APIs
in Swift safely there has to be a way to annotate individual parameters and result types
with relevant attributes that indicate that e.g. a block is called on a particular actor
or it accepts a Sendable or global-actor (i.e. ``@MainActor``) isolated parameter.

For example:

.. code-block:: objc

@interface MyService
-(void) handle: (void (^ __attribute__((swift_attr("@Sendable"))))(id)) handler;
@end

- Clang now disallows more than one ``__attribute__((ownership_returns(class, idx)))`` with
different class names attached to one function.

Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1719,8 +1719,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const;

QualType getAttributedType(attr::Kind attrKind, QualType modifiedType,
QualType equivalentType,
const Attr *attr = nullptr) const;

QualType getAttributedType(const Attr *attr, QualType modifiedType,
QualType equivalentType) const;

QualType getAttributedType(NullabilityKind nullability, QualType modifiedType,
QualType equivalentType);

QualType getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
QualType Wrapped) const;

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/PropertiesBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def APValue : PropertyType { let PassByReference = 1; }
def APValueKind : EnumPropertyType<"APValue::ValueKind">;
def ArraySizeModifier : EnumPropertyType<"ArraySizeModifier">;
def AttrKind : EnumPropertyType<"attr::Kind">;
def Attr : PropertyType<"const Attr *">;
def AutoTypeKeyword : EnumPropertyType;
def Bool : PropertyType<"bool">;
def BuiltinTypeKind : EnumPropertyType<"BuiltinType::Kind">;
Expand Down
42 changes: 17 additions & 25 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class ValueDecl;
class TagDecl;
class TemplateParameterList;
class Type;
class Attr;

enum {
TypeAlignmentInBits = 4,
Expand Down Expand Up @@ -6130,21 +6131,29 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
private:
friend class ASTContext; // ASTContext creates these

const Attr *Attribute;

QualType ModifiedType;
QualType EquivalentType;

AttributedType(QualType canon, attr::Kind attrKind, QualType modified,
QualType equivalent)
: Type(Attributed, canon, equivalent->getDependence()),
ModifiedType(modified), EquivalentType(equivalent) {
AttributedTypeBits.AttrKind = attrKind;
}
: AttributedType(canon, attrKind, nullptr, modified, equivalent) {}

AttributedType(QualType canon, const Attr *attr, QualType modified,
QualType equivalent);

private:
AttributedType(QualType canon, attr::Kind attrKind, const Attr *attr,
QualType modified, QualType equivalent);

public:
Kind getAttrKind() const {
return static_cast<Kind>(AttributedTypeBits.AttrKind);
}

const Attr *getAttr() const { return Attribute; }

QualType getModifiedType() const { return ModifiedType; }
QualType getEquivalentType() const { return EquivalentType; }

Expand Down Expand Up @@ -6176,25 +6185,6 @@ class AttributedType : public Type, public llvm::FoldingSetNode {

std::optional<NullabilityKind> getImmediateNullability() const;

/// Retrieve the attribute kind corresponding to the given
/// nullability kind.
static Kind getNullabilityAttrKind(NullabilityKind kind) {
switch (kind) {
case NullabilityKind::NonNull:
return attr::TypeNonNull;

case NullabilityKind::Nullable:
return attr::TypeNullable;

case NullabilityKind::NullableResult:
return attr::TypeNullableResult;

case NullabilityKind::Unspecified:
return attr::TypeNullUnspecified;
}
llvm_unreachable("Unknown nullability kind.");
}

/// Strip off the top-level nullability annotation on the given
/// type, if it's there.
///
Expand All @@ -6207,14 +6197,16 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
static std::optional<NullabilityKind> stripOuterNullability(QualType &T);

void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getAttrKind(), ModifiedType, EquivalentType);
Profile(ID, getAttrKind(), ModifiedType, EquivalentType, Attribute);
}

static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind,
QualType modified, QualType equivalent) {
QualType modified, QualType equivalent,
const Attr *attr) {
ID.AddInteger(attrKind);
ID.AddPointer(modified.getAsOpaquePtr());
ID.AddPointer(equivalent.getAsOpaquePtr());
ID.AddPointer(attr);
}

static bool classof(const Type *T) {
Expand Down
8 changes: 6 additions & 2 deletions clang/include/clang/AST/TypeProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -668,12 +668,16 @@ let Class = AttributedType in {
def : Property<"equivalentType", QualType> {
let Read = [{ node->getEquivalentType() }];
}
def : Property<"attribute", AttrKind> {
def : Property<"attrKind", AttrKind> {
let Read = [{ node->getAttrKind() }];
}
def : Property<"attribute", Attr> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there reason to store both attribute and attrKind here? Should we just implement attrKind as attribute.getKind ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, Attr is not always available (nullability related attributes only have a kind and don't allocate Attr).

let Read = [{ node->getAttr() }];
}

def : Creator<[{
return ctx.getAttributedType(attribute, modifiedType, equivalentType);
return ctx.getAttributedType(attrKind, modifiedType,
equivalentType, attribute);
}]>;
}

Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -2838,7 +2838,7 @@ def SwiftAsyncName : InheritableAttr {
let Documentation = [SwiftAsyncNameDocs];
}

def SwiftAttr : InheritableAttr {
def SwiftAttr : DeclOrTypeAttr {
let Spellings = [GNU<"swift_attr">];
let Args = [StringArgument<"Attribute">];
let Documentation = [SwiftAttrDocs];
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -4507,8 +4507,8 @@ def SwiftAttrDocs : Documentation {
let Heading = "swift_attr";
let Content = [{
The ``swift_attr`` provides a Swift-specific annotation for the declaration
to which the attribute appertains to. It can be used on any declaration
in Clang. This kind of annotation is ignored by Clang as it doesn't have any
or type to which the attribute appertains to. It can be used on any declaration
or type in Clang. This kind of annotation is ignored by Clang as it doesn't have any
semantic meaning in languages supported by Clang. The Swift compiler can
interpret these annotations according to its own rules when importing C or
Objective-C declarations.
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Serialization/ASTRecordWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ class ASTRecordWriter
AddStmt(const_cast<Stmt*>(S));
}

void writeAttr(const Attr *A) { AddAttr(A); }

/// Write an BTFTypeTagAttr object.
void writeBTFTypeTagAttr(const BTFTypeTagAttr *A) { AddAttr(A); }

Expand Down
48 changes: 40 additions & 8 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3552,7 +3552,8 @@ ASTContext::adjustType(QualType Orig,
const auto *AT = dyn_cast<AttributedType>(Orig);
return getAttributedType(AT->getAttrKind(),
adjustType(AT->getModifiedType(), Adjust),
adjustType(AT->getEquivalentType(), Adjust));
adjustType(AT->getEquivalentType(), Adjust),
AT->getAttr());
}

case Type::BTFTagAttributed: {
Expand Down Expand Up @@ -5197,24 +5198,54 @@ QualType ASTContext::getUnresolvedUsingType(

QualType ASTContext::getAttributedType(attr::Kind attrKind,
QualType modifiedType,
QualType equivalentType) const {
QualType equivalentType,
const Attr *attr) const {
llvm::FoldingSetNodeID id;
AttributedType::Profile(id, attrKind, modifiedType, equivalentType);
AttributedType::Profile(id, attrKind, modifiedType, equivalentType, attr);

void *insertPos = nullptr;
AttributedType *type = AttributedTypes.FindNodeOrInsertPos(id, insertPos);
if (type) return QualType(type, 0);

assert(!attr || attr->getKind() == attrKind);

QualType canon = getCanonicalType(equivalentType);
type = new (*this, alignof(AttributedType))
AttributedType(canon, attrKind, modifiedType, equivalentType);
type = new (*this, alignof(AttributedType))
AttributedType(canon, attrKind, attr, modifiedType, equivalentType);

Types.push_back(type);
AttributedTypes.InsertNode(type, insertPos);

return QualType(type, 0);
}

QualType ASTContext::getAttributedType(const Attr *attr, QualType modifiedType,
QualType equivalentType) const {
return getAttributedType(attr->getKind(), modifiedType, equivalentType, attr);
}

QualType ASTContext::getAttributedType(NullabilityKind nullability,
QualType modifiedType,
QualType equivalentType) {
switch (nullability) {
case NullabilityKind::NonNull:
return getAttributedType(attr::TypeNonNull, modifiedType, equivalentType);

case NullabilityKind::Nullable:
return getAttributedType(attr::TypeNullable, modifiedType, equivalentType);

case NullabilityKind::NullableResult:
return getAttributedType(attr::TypeNullableResult, modifiedType,
equivalentType);

case NullabilityKind::Unspecified:
return getAttributedType(attr::TypeNullUnspecified, modifiedType,
equivalentType);
}

llvm_unreachable("Unknown nullability kind");
}

QualType ASTContext::getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
QualType Wrapped) const {
llvm::FoldingSetNodeID ID;
Expand Down Expand Up @@ -7537,8 +7568,8 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) const {

// int x[_Nullable] -> int * _Nullable
if (auto Nullability = Ty->getNullability()) {
Result = const_cast<ASTContext *>(this)->getAttributedType(
AttributedType::getNullabilityAttrKind(*Nullability), Result, Result);
Result = const_cast<ASTContext *>(this)->getAttributedType(*Nullability,
Result, Result);
}
return Result;
}
Expand Down Expand Up @@ -13773,7 +13804,8 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
return QualType();
// FIXME: It's inefficient to have to unify the modified types.
return Ctx.getAttributedType(Kind, Ctx.getCommonSugaredType(MX, MY),
Ctx.getQualifiedType(Underlying));
Ctx.getQualifiedType(Underlying),
AX->getAttr());
}
case Type::BTFTagAttributed: {
const auto *BX = cast<BTFTagAttributedType>(X);
Expand Down
6 changes: 2 additions & 4 deletions clang/lib/AST/ASTDiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
QualType SugarRT = FT->getReturnType();
QualType RT = desugarForDiagnostic(Context, SugarRT, DesugarReturn);
if (auto nullability = AttributedType::stripOuterNullability(SugarRT)) {
RT = Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*nullability), RT, RT);
RT = Context.getAttributedType(*nullability, RT, RT);
}

bool DesugarArgument = false;
Expand All @@ -97,8 +96,7 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
QualType PT = desugarForDiagnostic(Context, SugarPT, DesugarArgument);
if (auto nullability =
AttributedType::stripOuterNullability(SugarPT)) {
PT = Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*nullability), PT, PT);
PT = Context.getAttributedType(*nullability, PT, PT);
}
Args.push_back(PT);
}
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1580,8 +1580,9 @@ ExpectedType ASTNodeImporter::VisitAttributedType(const AttributedType *T) {
if (!ToEquivalentTypeOrErr)
return ToEquivalentTypeOrErr.takeError();

return Importer.getToContext().getAttributedType(T->getAttrKind(),
*ToModifiedTypeOrErr, *ToEquivalentTypeOrErr);
return Importer.getToContext().getAttributedType(
T->getAttrKind(), *ToModifiedTypeOrErr, *ToEquivalentTypeOrErr,
T->getAttr());
}

ExpectedType
Expand Down
20 changes: 17 additions & 3 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1241,8 +1241,8 @@ struct SimpleTransformVisitor : public TypeVisitor<Derived, QualType> {
== T->getEquivalentType().getAsOpaquePtr())
return QualType(T, 0);

return Ctx.getAttributedType(T->getAttrKind(), modifiedType,
equivalentType);
return Ctx.getAttributedType(T->getAttrKind(), modifiedType, equivalentType,
T->getAttr());
}

QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
Expand Down Expand Up @@ -1545,7 +1545,8 @@ struct SubstObjCTypeArgsVisitor

// Rebuild the attributed type.
return Ctx.getAttributedType(newAttrType->getAttrKind(),
newAttrType->getModifiedType(), newEquivType);
newAttrType->getModifiedType(), newEquivType,
newAttrType->getAttr());
}
};

Expand Down Expand Up @@ -4115,6 +4116,19 @@ bool RecordType::hasConstFields() const {
return false;
}

AttributedType::AttributedType(QualType canon, const Attr *attr,
QualType modified, QualType equivalent)
: AttributedType(canon, attr->getKind(), attr, modified, equivalent) {}

AttributedType::AttributedType(QualType canon, attr::Kind attrKind,
const Attr *attr, QualType modified,
QualType equivalent)
: Type(Attributed, canon, equivalent->getDependence()), Attribute(attr),
ModifiedType(modified), EquivalentType(equivalent) {
AttributedTypeBits.AttrKind = attrKind;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it'd be lovely to get these bits back. Perhaps just remove attrKind from this ctor and just implement the above one instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think we can do that, see https://github.com/llvm/llvm-project/pull/108631/files#r1823004595. @Xazax-hun had a comment to that effect already.

assert(!attr || attr->getKind() == attrKind);
}

bool AttributedType::isQualifier() const {
// FIXME: Generate this with TableGen.
switch (getAttrKind()) {
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1934,6 +1934,14 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
return;
}

if (T->getAttrKind() == attr::SwiftAttr) {
if (auto *swiftAttr = dyn_cast_or_null<SwiftAttrAttr>(T->getAttr())) {
OS << " __attribute__((swift_attr(\"" << swiftAttr->getAttribute()
<< "\")))";
}
return;
}

OS << " __attribute__((";
switch (T->getAttrKind()) {
#define TYPE_ATTR(NAME)
Expand Down Expand Up @@ -1994,6 +2002,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::NonAllocating:
case attr::Blocking:
case attr::Allocating:
case attr::SwiftAttr:
llvm_unreachable("This attribute should have been handled already");

case attr::NSReturnsRetained:
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3332,9 +3332,7 @@ static void mergeParamDeclTypes(ParmVarDecl *NewParam,
}
} else {
QualType NewT = NewParam->getType();
NewT = S.Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*Oldnullability),
NewT, NewT);
NewT = S.Context.getAttributedType(*Oldnullability, NewT, NewT);
NewParam->setType(NewT);
}
}
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/Sema/SemaDeclObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4572,9 +4572,7 @@ static QualType mergeTypeNullabilityForRedecl(Sema &S, SourceLocation loc,
return type;

// Otherwise, provide the result with the same nullability.
return S.Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*prevNullability),
type, type);
return S.Context.getAttributedType(*prevNullability, type, type);
}

/// Merge information from the declaration of a method in the \@interface
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8757,8 +8757,7 @@ static QualType computeConditionalNullability(QualType ResTy, bool IsBin,
ResTy = ResTy.getSingleStepDesugaredType(Ctx);

// Create a new AttributedType with the new nullability kind.
auto NewAttr = AttributedType::getNullabilityAttrKind(MergedKind);
return Ctx.getAttributedType(NewAttr, ResTy, ResTy);
return Ctx.getAttributedType(MergedKind, ResTy, ResTy);
}

ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
Expand Down
Loading
Loading