[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
egorzhdan wrote: Apologies for the delay! I looked into this performance hit, and it seems largely expected to me: the compiler spends extra time checking if there is an apinotes file for a given clang module with the notes for the declarations that are being processed. We can consider adding a Clang driver option to disable API Notes, if this performance regression is significant enough. https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
aeubanks wrote: > Oh, thanks @nikic for that data point. Let me try to avoid the overhead, I'll > put up a patch tomorrow morning. Did this ever happen? https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
egorzhdan wrote: Oh, thanks @nikic for that data point. Let me try to avoid the overhead, I'll put up a patch tomorrow morning. https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
nikic wrote: FYI this change adds some overhead (about 0.2% for O0) builds (http://llvm-compile-time-tracker.com/compare.php?from=046682ef88a254443e8620bfd48b35bfa0a83809=440b1743ee0c8bfb7bf0c4b503bde5ab9af88dc0=instructions:u). Is it possible to avoid it for people not using API notes? https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
https://github.com/egorzhdan closed https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + auto IsUnmodified = [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> bool { +QualType Original = QT; +S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), +isa(D), +/*OverrideExisting=*/true); +return QT.getTypePtr() == Original.getTypePtr(); + }; + + if (auto Function = dyn_cast(D)) { +if (!IsUnmodified(D, Function->getReturnType(), Nullability)) { + QualType FnType = Function->getType(); + Function->setType(FnType); +} + } else if (auto Method = dyn_cast(D)) { +QualType Type = Method->getReturnType(); +if (!IsUnmodified(D, Type, Nullability)) { + Method->setReturnType(Type); + + // Make it a context-sensitive keyword if we can. + if (!isIndirectPointerType(Type)) +Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Value = dyn_cast(D)) { +QualType Type = Value->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Value->setType(Type); + + // Make it a context-sensitive keyword if we can. + if (auto Parm = dyn_cast(D)) { +if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type)) + Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + } +} + } else if (auto Property = dyn_cast(D)) { +QualType Type = Property->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Property->setType(Type, Property->getTypeSourceInfo()); + + // Make it a property attribute if we can. + if (!isIndirectPointerType(Type)) +Property->setPropertyAttributes( +ObjCPropertyAttribute::kind_null_resettable); +} + } +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef ASTAllocateString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char *)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getPlaceholderAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X) \ + template <> struct AttrKindFor { \ +static const attr::Kind value = attr::X; \ + }; +#include "clang/Basic/AttrList.inc" + +/// Handle an attribute introduced by API notes. +/// +/// \param IsAddition Whether we should add
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + auto IsUnmodified = [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> bool { +QualType Original = QT; +S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), +isa(D), +/*OverrideExisting=*/true); +return QT.getTypePtr() == Original.getTypePtr(); + }; + + if (auto Function = dyn_cast(D)) { +if (!IsUnmodified(D, Function->getReturnType(), Nullability)) { + QualType FnType = Function->getType(); + Function->setType(FnType); +} + } else if (auto Method = dyn_cast(D)) { +QualType Type = Method->getReturnType(); +if (!IsUnmodified(D, Type, Nullability)) { + Method->setReturnType(Type); + + // Make it a context-sensitive keyword if we can. + if (!isIndirectPointerType(Type)) +Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Value = dyn_cast(D)) { +QualType Type = Value->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Value->setType(Type); + + // Make it a context-sensitive keyword if we can. + if (auto Parm = dyn_cast(D)) { +if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type)) + Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + } +} + } else if (auto Property = dyn_cast(D)) { +QualType Type = Property->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Property->setType(Type, Property->getTypeSourceInfo()); + + // Make it a property attribute if we can. + if (!isIndirectPointerType(Type)) +Property->setPropertyAttributes( +ObjCPropertyAttribute::kind_null_resettable); +} + } +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef ASTAllocateString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char *)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getPlaceholderAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X) \ + template <> struct AttrKindFor { \ +static const attr::Kind value = attr::X; \ + }; +#include "clang/Basic/AttrList.inc" + +/// Handle an attribute introduced by API notes. +/// +/// \param IsAddition Whether we should add
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + auto IsUnmodified = [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> bool { +QualType Original = QT; +S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), +isa(D), +/*OverrideExisting=*/true); +return QT.getTypePtr() == Original.getTypePtr(); + }; + + if (auto Function = dyn_cast(D)) { +if (!IsUnmodified(D, Function->getReturnType(), Nullability)) { + QualType FnType = Function->getType(); + Function->setType(FnType); +} + } else if (auto Method = dyn_cast(D)) { +QualType Type = Method->getReturnType(); +if (!IsUnmodified(D, Type, Nullability)) { + Method->setReturnType(Type); + + // Make it a context-sensitive keyword if we can. + if (!isIndirectPointerType(Type)) +Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Value = dyn_cast(D)) { +QualType Type = Value->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Value->setType(Type); + + // Make it a context-sensitive keyword if we can. + if (auto Parm = dyn_cast(D)) { +if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type)) + Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + } +} + } else if (auto Property = dyn_cast(D)) { +QualType Type = Property->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Property->setType(Type, Property->getTypeSourceInfo()); + + // Make it a property attribute if we can. + if (!isIndirectPointerType(Type)) +Property->setPropertyAttributes( +ObjCPropertyAttribute::kind_null_resettable); +} + } +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef ASTAllocateString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char *)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getPlaceholderAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X) \ + template <> struct AttrKindFor { \ +static const attr::Kind value = attr::X; \ + }; +#include "clang/Basic/AttrList.inc" + +/// Handle an attribute introduced by API notes. +/// +/// \param IsAddition Whether we should add
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + auto IsUnmodified = [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> bool { +QualType Original = QT; +S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), +isa(D), +/*OverrideExisting=*/true); +return QT.getTypePtr() == Original.getTypePtr(); + }; + + if (auto Function = dyn_cast(D)) { +if (!IsUnmodified(D, Function->getReturnType(), Nullability)) { + QualType FnType = Function->getType(); + Function->setType(FnType); +} + } else if (auto Method = dyn_cast(D)) { +QualType Type = Method->getReturnType(); +if (!IsUnmodified(D, Type, Nullability)) { + Method->setReturnType(Type); + + // Make it a context-sensitive keyword if we can. + if (!isIndirectPointerType(Type)) +Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Value = dyn_cast(D)) { +QualType Type = Value->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Value->setType(Type); + + // Make it a context-sensitive keyword if we can. + if (auto Parm = dyn_cast(D)) { +if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type)) + Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + } +} + } else if (auto Property = dyn_cast(D)) { +QualType Type = Property->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Property->setType(Type, Property->getTypeSourceInfo()); + + // Make it a property attribute if we can. + if (!isIndirectPointerType(Type)) +Property->setPropertyAttributes( +ObjCPropertyAttribute::kind_null_resettable); +} + } +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef ASTAllocateString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char *)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getPlaceholderAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X) \ + template <> struct AttrKindFor { \ +static const attr::Kind value = attr::X; \ + }; +#include "clang/Basic/AttrList.inc" + +/// Handle an attribute introduced by API notes. +/// +/// \param IsAddition Whether we should add
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + auto IsUnmodified = [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> bool { +QualType Original = QT; +S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), +isa(D), +/*OverrideExisting=*/true); +return QT.getTypePtr() == Original.getTypePtr(); + }; + + if (auto Function = dyn_cast(D)) { +if (!IsUnmodified(D, Function->getReturnType(), Nullability)) { egorzhdan wrote: Agreed, done. https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; egorzhdan wrote: `State` seems a bit too generic of a name to me, and these are still `bool`s so they won't get more cases. I renamed `IsReplacement_t` to `IsSubstitution_t`, but I would prefer to leave `IsActive_t` as is. https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/78445 >From 806fe5abaeec7ad7d75d0be026bb42808d15bc41 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 17 Jan 2024 13:41:25 + Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../clang/Basic/DiagnosticSemaKinds.td| 7 + clang/include/clang/Sema/Sema.h | 6 + clang/lib/Sema/CMakeLists.txt | 1 + clang/lib/Sema/SemaAPINotes.cpp | 988 ++ clang/lib/Sema/SemaDecl.cpp | 4 + clang/lib/Sema/SemaDeclAttr.cpp | 3 + clang/lib/Sema/SemaDeclCXX.cpp| 6 +- clang/lib/Sema/SemaDeclObjC.cpp | 4 + clang/lib/Sema/SemaObjCProperty.cpp | 5 + clang/lib/Sema/SemaTemplate.cpp | 7 + 10 files changed, 1030 insertions(+), 1 deletion(-) create mode 100644 clang/lib/Sema/SemaAPINotes.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ebda201361fb07..887d6120f48d2c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning< } // end of sema category +let CategoryName = "API Notes Issue" in { + +def err_incompatible_replacement_type : Error< + "API notes replacement type %0 has a different size from original type %1">; + +} // end of API Notes category + let CategoryName = "OpenMP Issue" in { // OpenMP support. def err_omp_expected_var_arg : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fcccac10f4733a..77749372b7fb65 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4883,6 +4883,12 @@ class Sema final { bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr , bool SkipArgCountCheck = false); + /// Map any API notes provided for this declaration to attributes on the + /// declaration. + /// + /// Triggered by declaration-attribute processing. + void ProcessAPINotes(Decl *D); + /// Determine if type T is a valid subject for a nonnull and similar /// attributes. By default, we look through references (the behavior used by /// nonnull), but if the second parameter is true, then we treat a reference diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 862f9d4ffb825d..e8bff07ced0cfa 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -27,6 +27,7 @@ add_clang_library(clangSema Sema.cpp SemaAccess.cpp SemaAttr.cpp + SemaAPINotes.cpp SemaAvailability.cpp SemaCXXScopeSpec.cpp SemaCast.cpp diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp new file mode 100644 index 00..836c633e9d2042 --- /dev/null +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -0,0 +1,988 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsSubstitution_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsSubstitution_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsSubstitution_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + auto IsUnmodified = [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> bool { +QualType Original = QT; +S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), +isa(D), +/*OverrideExisting=*/true); +return QT.getTypePtr() == Original.getTypePtr(); + }; + + if (auto Function = dyn_cast(D)) { +if (!IsUnmodified(D, Function->getReturnType(), Nullability)) { + QualType FnType = Function->getType(); + Function->setType(FnType); +} + } else if (auto Method = dyn_cast(D)) { +QualType Type = Method->getReturnType(); +if (!IsUnmodified(D, Type, Nullability)) { + Method->setReturnType(Type); + + // Make it a context-sensitive keyword if we can. + if (!isIndirectPointerType(Type)) +Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Value = dyn_cast(D)) { +QualType Type = Value->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Value->setType(Type); + + // Make it a context-sensitive keyword if we can. + if (auto Parm = dyn_cast(D)) { +if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type)) + Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + } +} + } else if (auto Property = dyn_cast(D)) { +QualType Type = Property->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Property->setType(Type, Property->getTypeSourceInfo()); + + // Make it a property attribute if we can. + if (!isIndirectPointerType(Type)) +Property->setPropertyAttributes( +ObjCPropertyAttribute::kind_null_resettable); +} + } +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef ASTAllocateString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char *)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getPlaceholderAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X) \ + template <> struct AttrKindFor { \ +static const attr::Kind value = attr::X; \ + }; +#include "clang/Basic/AttrList.inc" + +/// Handle an attribute introduced by API notes. +/// +/// \param IsAddition Whether we should add
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + auto IsUnmodified = [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> bool { +QualType Original = QT; +S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), +isa(D), +/*OverrideExisting=*/true); +return QT.getTypePtr() == Original.getTypePtr(); + }; + + if (auto Function = dyn_cast(D)) { +if (!IsUnmodified(D, Function->getReturnType(), Nullability)) { + QualType FnType = Function->getType(); + Function->setType(FnType); +} + } else if (auto Method = dyn_cast(D)) { +QualType Type = Method->getReturnType(); +if (!IsUnmodified(D, Type, Nullability)) { + Method->setReturnType(Type); + + // Make it a context-sensitive keyword if we can. + if (!isIndirectPointerType(Type)) +Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Value = dyn_cast(D)) { +QualType Type = Value->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Value->setType(Type); + + // Make it a context-sensitive keyword if we can. + if (auto Parm = dyn_cast(D)) { +if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type)) + Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + } +} + } else if (auto Property = dyn_cast(D)) { +QualType Type = Property->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Property->setType(Type, Property->getTypeSourceInfo()); + + // Make it a property attribute if we can. + if (!isIndirectPointerType(Type)) +Property->setPropertyAttributes( +ObjCPropertyAttribute::kind_null_resettable); +} + } +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef ASTAllocateString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char *)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getPlaceholderAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X) \ + template <> struct AttrKindFor { \ +static const attr::Kind value = attr::X; \ + }; +#include "clang/Basic/AttrList.inc" + +/// Handle an attribute introduced by API notes. +/// +/// \param IsAddition Whether we should add
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + auto IsUnmodified = [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> bool { +QualType Original = QT; +S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), +isa(D), +/*OverrideExisting=*/true); +return QT.getTypePtr() == Original.getTypePtr(); + }; + + if (auto Function = dyn_cast(D)) { +if (!IsUnmodified(D, Function->getReturnType(), Nullability)) { + QualType FnType = Function->getType(); + Function->setType(FnType); +} + } else if (auto Method = dyn_cast(D)) { +QualType Type = Method->getReturnType(); +if (!IsUnmodified(D, Type, Nullability)) { + Method->setReturnType(Type); + + // Make it a context-sensitive keyword if we can. + if (!isIndirectPointerType(Type)) +Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Value = dyn_cast(D)) { +QualType Type = Value->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Value->setType(Type); + + // Make it a context-sensitive keyword if we can. + if (auto Parm = dyn_cast(D)) { +if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type)) + Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + } +} + } else if (auto Property = dyn_cast(D)) { +QualType Type = Property->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Property->setType(Type, Property->getTypeSourceInfo()); + + // Make it a property attribute if we can. + if (!isIndirectPointerType(Type)) +Property->setPropertyAttributes( +ObjCPropertyAttribute::kind_null_resettable); +} + } +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef ASTAllocateString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char *)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getPlaceholderAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X) \ + template <> struct AttrKindFor { \ +static const attr::Kind value = attr::X; \ + }; +#include "clang/Basic/AttrList.inc" + +/// Handle an attribute introduced by API notes. +/// +/// \param IsAddition Whether we should add
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + auto IsUnmodified = [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> bool { +QualType Original = QT; +S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), +isa(D), +/*OverrideExisting=*/true); +return QT.getTypePtr() == Original.getTypePtr(); + }; + + if (auto Function = dyn_cast(D)) { +if (!IsUnmodified(D, Function->getReturnType(), Nullability)) { + QualType FnType = Function->getType(); + Function->setType(FnType); +} + } else if (auto Method = dyn_cast(D)) { +QualType Type = Method->getReturnType(); +if (!IsUnmodified(D, Type, Nullability)) { + Method->setReturnType(Type); + + // Make it a context-sensitive keyword if we can. + if (!isIndirectPointerType(Type)) +Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Value = dyn_cast(D)) { +QualType Type = Value->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Value->setType(Type); + + // Make it a context-sensitive keyword if we can. + if (auto Parm = dyn_cast(D)) { +if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type)) + Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + } +} + } else if (auto Property = dyn_cast(D)) { +QualType Type = Property->getType(); +if (!IsUnmodified(D, Type, Nullability)) { + Property->setType(Type, Property->getTypeSourceInfo()); + + // Make it a property attribute if we can. + if (!isIndirectPointerType(Type)) +Property->setPropertyAttributes( +ObjCPropertyAttribute::kind_null_resettable); +} + } +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef ASTAllocateString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char *)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getPlaceholderAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X) \ + template <> struct AttrKindFor { \ +static const attr::Kind value = attr::X; \ + }; +#include "clang/Basic/AttrList.inc" + +/// Handle an attribute introduced by API notes. +/// +/// \param IsAddition Whether we should add
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
https://github.com/compnerd approved this pull request. Most of the new comments are nits and small readability tweaks. I still would like to avoid the double `dyn_cast` checks, but I don't know if this is worth holding up on at that point. Thank you for the multiple rounds on this and sorry about the delay, the length made it daunting. https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + auto IsUnmodified = [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> bool { +QualType Original = QT; +S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), +isa(D), +/*OverrideExisting=*/true); +return QT.getTypePtr() == Original.getTypePtr(); + }; + + if (auto Function = dyn_cast(D)) { +if (!IsUnmodified(D, Function->getReturnType(), Nullability)) { compnerd wrote: An alternative to consider: rename the function to `IsModified` and return the negated value so simplify the callees. https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; compnerd wrote: I'd consider renaming these now with the `enum class`: ```suggestion enum class State : bool { Inactive, Active }; enum class SubstitutionType : bool { Original, Replacement }; ``` https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
https://github.com/compnerd edited https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + auto IsUnmodified = [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> bool { +QualType Original = QT; +S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), +isa(D), +/*OverrideExisting=*/true); +return QT.getTypePtr() == Original.getTypePtr(); + }; + + if (auto Function = dyn_cast(D)) { +if (IsUnmodified(D, Function->getReturnType(), Nullability)) { egorzhdan wrote: Oops, my bad, fixed. https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/78445 >From 2e4aa8640d208767a3f560516f1b3fd8c31dee3f Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 17 Jan 2024 13:41:25 + Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../clang/Basic/DiagnosticSemaKinds.td| 7 + clang/include/clang/Sema/Sema.h | 6 + clang/lib/Sema/CMakeLists.txt | 1 + clang/lib/Sema/SemaAPINotes.cpp | 989 ++ clang/lib/Sema/SemaDecl.cpp | 4 + clang/lib/Sema/SemaDeclAttr.cpp | 3 + clang/lib/Sema/SemaDeclCXX.cpp| 6 +- clang/lib/Sema/SemaDeclObjC.cpp | 4 + clang/lib/Sema/SemaObjCProperty.cpp | 5 + clang/lib/Sema/SemaTemplate.cpp | 7 + 10 files changed, 1031 insertions(+), 1 deletion(-) create mode 100644 clang/lib/Sema/SemaAPINotes.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ebda201361fb07..887d6120f48d2c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning< } // end of sema category +let CategoryName = "API Notes Issue" in { + +def err_incompatible_replacement_type : Error< + "API notes replacement type %0 has a different size from original type %1">; + +} // end of API Notes category + let CategoryName = "OpenMP Issue" in { // OpenMP support. def err_omp_expected_var_arg : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fcccac10f4733a..77749372b7fb65 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4883,6 +4883,12 @@ class Sema final { bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr , bool SkipArgCountCheck = false); + /// Map any API notes provided for this declaration to attributes on the + /// declaration. + /// + /// Triggered by declaration-attribute processing. + void ProcessAPINotes(Decl *D); + /// Determine if type T is a valid subject for a nonnull and similar /// attributes. By default, we look through references (the behavior used by /// nonnull), but if the second parameter is true, then we treat a reference diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 862f9d4ffb825d..e8bff07ced0cfa 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -27,6 +27,7 @@ add_clang_library(clangSema Sema.cpp SemaAccess.cpp SemaAttr.cpp + SemaAPINotes.cpp SemaAvailability.cpp SemaCXXScopeSpec.cpp SemaCast.cpp diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp new file mode 100644 index 00..e75df0653c1f9b --- /dev/null +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + auto IsUnmodified = [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> bool { +QualType Original = QT; +S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), +isa(D), +/*OverrideExisting=*/true); +return QT.getTypePtr() == Original.getTypePtr(); + }; + + if (auto Function = dyn_cast(D)) { +if (IsUnmodified(D, Function->getReturnType(), Nullability)) { + QualType FnType = Function->getType(); + Function->setType(FnType); +} + } else if (auto Method = dyn_cast(D)) { +QualType Type = Method->getReturnType(); +if (IsUnmodified(D, Type, Nullability)) { + Method->setReturnType(Type); + + // Make it a context-sensitive keyword if we can. + if (!isIndirectPointerType(Type)) +Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Value = dyn_cast(D)) { +QualType Type = Value->getType(); +if (IsUnmodified(D, Type, Nullability)) { compnerd wrote: And here https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + auto IsUnmodified = [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> bool { +QualType Original = QT; +S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), +isa(D), +/*OverrideExisting=*/true); +return QT.getTypePtr() == Original.getTypePtr(); + }; + + if (auto Function = dyn_cast(D)) { +if (IsUnmodified(D, Function->getReturnType(), Nullability)) { + QualType FnType = Function->getType(); + Function->setType(FnType); +} + } else if (auto Method = dyn_cast(D)) { +QualType Type = Method->getReturnType(); +if (IsUnmodified(D, Type, Nullability)) { + Method->setReturnType(Type); + + // Make it a context-sensitive keyword if we can. + if (!isIndirectPointerType(Type)) +Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Value = dyn_cast(D)) { +QualType Type = Value->getType(); +if (IsUnmodified(D, Type, Nullability)) { + Value->setType(Type); + + // Make it a context-sensitive keyword if we can. + if (auto Parm = dyn_cast(D)) { +if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type)) + Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + } +} + } else if (auto Property = dyn_cast(D)) { +QualType Type = Property->getType(); +if (IsUnmodified(D, Type, Nullability)) { compnerd wrote: And here https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + auto IsUnmodified = [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> bool { +QualType Original = QT; +S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), +isa(D), +/*OverrideExisting=*/true); +return QT.getTypePtr() == Original.getTypePtr(); + }; + + if (auto Function = dyn_cast(D)) { +if (IsUnmodified(D, Function->getReturnType(), Nullability)) { compnerd wrote: Wait if there is no change to the nullability, why reset the type? https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + auto IsUnmodified = [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> bool { +QualType Original = QT; +S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), +isa(D), +/*OverrideExisting=*/true); +return QT.getTypePtr() == Original.getTypePtr(); + }; + + if (auto Function = dyn_cast(D)) { +if (IsUnmodified(D, Function->getReturnType(), Nullability)) { + QualType FnType = Function->getType(); + Function->setType(FnType); +} + } else if (auto Method = dyn_cast(D)) { +QualType Type = Method->getReturnType(); +if (IsUnmodified(D, Type, Nullability)) { compnerd wrote: Similar https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; egorzhdan wrote: Ah, I see, thanks for explaining! Done https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/78445 >From 40a6247d20e121d9dea0ff83a61f5e7abba7bba6 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 17 Jan 2024 13:41:25 + Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../clang/Basic/DiagnosticSemaKinds.td| 7 + clang/include/clang/Sema/Sema.h | 6 + clang/lib/Sema/CMakeLists.txt | 1 + clang/lib/Sema/SemaAPINotes.cpp | 989 ++ clang/lib/Sema/SemaDecl.cpp | 4 + clang/lib/Sema/SemaDeclAttr.cpp | 3 + clang/lib/Sema/SemaDeclCXX.cpp| 6 +- clang/lib/Sema/SemaDeclObjC.cpp | 4 + clang/lib/Sema/SemaObjCProperty.cpp | 5 + clang/lib/Sema/SemaTemplate.cpp | 7 + 10 files changed, 1031 insertions(+), 1 deletion(-) create mode 100644 clang/lib/Sema/SemaAPINotes.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ebda201361fb07..887d6120f48d2c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning< } // end of sema category +let CategoryName = "API Notes Issue" in { + +def err_incompatible_replacement_type : Error< + "API notes replacement type %0 has a different size from original type %1">; + +} // end of API Notes category + let CategoryName = "OpenMP Issue" in { // OpenMP support. def err_omp_expected_var_arg : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fcccac10f4733a..77749372b7fb65 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4883,6 +4883,12 @@ class Sema final { bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr , bool SkipArgCountCheck = false); + /// Map any API notes provided for this declaration to attributes on the + /// declaration. + /// + /// Triggered by declaration-attribute processing. + void ProcessAPINotes(Decl *D); + /// Determine if type T is a valid subject for a nonnull and similar /// attributes. By default, we look through references (the behavior used by /// nonnull), but if the second parameter is true, then we treat a reference diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 862f9d4ffb825d..e8bff07ced0cfa 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -27,6 +27,7 @@ add_clang_library(clangSema Sema.cpp SemaAccess.cpp SemaAttr.cpp + SemaAPINotes.cpp SemaAvailability.cpp SemaCXXScopeSpec.cpp SemaCast.cpp diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp new file mode 100644 index 00..594d73753a80e0 --- /dev/null +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -0,0 +1,989 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,995 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + + if (Type.isNull()) +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +QualType FnType = Function->getType(); +Function->setType(FnType); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isIndirectPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isIndirectPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); compnerd wrote: That should allow us to get rid of this as well. https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; compnerd wrote: I was thinking something like: ```c++ auto IsUnmodified = [](Decl *D, QualType QT, NullabilityKind Nullability) -> Bool { QualType Original = QT; S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), isa(D), /*OverrideExisting=*/true); return QT.getTypePtr() == Original.getTypePtr(); } ``` Then, we could just do an inline `if (IsUnmodified(...)) return;` allowing us to fold the two if slides together. https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/78445 >From c1ad33ed549affb2bdabf49be4340a6f7580b191 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 17 Jan 2024 13:41:25 + Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../clang/Basic/DiagnosticSemaKinds.td| 7 + clang/include/clang/Sema/Sema.h | 6 + clang/lib/Sema/CMakeLists.txt | 1 + clang/lib/Sema/SemaAPINotes.cpp | 995 ++ clang/lib/Sema/SemaDecl.cpp | 4 + clang/lib/Sema/SemaDeclAttr.cpp | 3 + clang/lib/Sema/SemaDeclCXX.cpp| 6 +- clang/lib/Sema/SemaDeclObjC.cpp | 4 + clang/lib/Sema/SemaObjCProperty.cpp | 5 + clang/lib/Sema/SemaTemplate.cpp | 7 + 10 files changed, 1037 insertions(+), 1 deletion(-) create mode 100644 clang/lib/Sema/SemaAPINotes.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ebda201361fb07..887d6120f48d2c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning< } // end of sema category +let CategoryName = "API Notes Issue" in { + +def err_incompatible_replacement_type : Error< + "API notes replacement type %0 has a different size from original type %1">; + +} // end of API Notes category + let CategoryName = "OpenMP Issue" in { // OpenMP support. def err_omp_expected_var_arg : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fcccac10f4733a..77749372b7fb65 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4883,6 +4883,12 @@ class Sema final { bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr , bool SkipArgCountCheck = false); + /// Map any API notes provided for this declaration to attributes on the + /// declaration. + /// + /// Triggered by declaration-attribute processing. + void ProcessAPINotes(Decl *D); + /// Determine if type T is a valid subject for a nonnull and similar /// attributes. By default, we look through references (the behavior used by /// nonnull), but if the second parameter is true, then we treat a reference diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 862f9d4ffb825d..e8bff07ced0cfa 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -27,6 +27,7 @@ add_clang_library(clangSema Sema.cpp SemaAccess.cpp SemaAttr.cpp + SemaAPINotes.cpp SemaAvailability.cpp SemaCXXScopeSpec.cpp SemaCast.cpp diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp new file mode 100644 index 00..9b19d3a3eb9ef2 --- /dev/null +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -0,0 +1,995 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; egorzhdan wrote: Hmm, not sure I follow, what can we convert to a lambda? We could theoretically convert the `dyn_cast`s to a `switch`, but that would mean we'd have to list all possible kinds of a `FunctionDecl` here, for instance. https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); egorzhdan wrote: Oh, good idea, let's do that! https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/78445 >From e7577bb881ee32e92037c1f10e63ac81756a4b66 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 17 Jan 2024 13:41:25 + Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../clang/Basic/DiagnosticSemaKinds.td|7 + clang/include/clang/Sema/Sema.h |6 + clang/lib/Sema/CMakeLists.txt |1 + clang/lib/Sema/SemaAPINotes.cpp | 1000 + clang/lib/Sema/SemaDecl.cpp |4 + clang/lib/Sema/SemaDeclAttr.cpp |3 + clang/lib/Sema/SemaDeclCXX.cpp|6 +- clang/lib/Sema/SemaDeclObjC.cpp |4 + clang/lib/Sema/SemaObjCProperty.cpp |5 + clang/lib/Sema/SemaTemplate.cpp |7 + 10 files changed, 1042 insertions(+), 1 deletion(-) create mode 100644 clang/lib/Sema/SemaAPINotes.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ebda201361fb07..887d6120f48d2c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning< } // end of sema category +let CategoryName = "API Notes Issue" in { + +def err_incompatible_replacement_type : Error< + "API notes replacement type %0 has a different size from original type %1">; + +} // end of API Notes category + let CategoryName = "OpenMP Issue" in { // OpenMP support. def err_omp_expected_var_arg : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fcccac10f4733a..77749372b7fb65 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4883,6 +4883,12 @@ class Sema final { bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr , bool SkipArgCountCheck = false); + /// Map any API notes provided for this declaration to attributes on the + /// declaration. + /// + /// Triggered by declaration-attribute processing. + void ProcessAPINotes(Decl *D); + /// Determine if type T is a valid subject for a nonnull and similar /// attributes. By default, we look through references (the behavior used by /// nonnull), but if the second parameter is true, then we treat a reference diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 862f9d4ffb825d..e8bff07ced0cfa 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -27,6 +27,7 @@ add_clang_library(clangSema Sema.cpp SemaAccess.cpp SemaAttr.cpp + SemaAPINotes.cpp SemaAvailability.cpp SemaCXXScopeSpec.cpp SemaCast.cpp diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp new file mode 100644 index 00..5a126ecc4016e4 --- /dev/null +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -0,0 +1,1000 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { egorzhdan wrote: Fixed https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { egorzhdan wrote: Renamed it to `ASTAllocateString`. https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); egorzhdan wrote: Good catch! That should be `alignof(char *)`. https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; egorzhdan wrote: Yeap, done https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { egorzhdan wrote: Alright, renamed it https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; egorzhdan wrote: Done https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; egorzhdan wrote: Done https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/78445 >From 76876c599efe1a51019407a261a812891b362a47 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 17 Jan 2024 13:41:25 + Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../clang/Basic/DiagnosticSemaKinds.td|7 + clang/include/clang/Sema/Sema.h |6 + clang/lib/Sema/CMakeLists.txt |1 + clang/lib/Sema/SemaAPINotes.cpp | 1003 + clang/lib/Sema/SemaDecl.cpp |4 + clang/lib/Sema/SemaDeclAttr.cpp |3 + clang/lib/Sema/SemaDeclCXX.cpp|6 +- clang/lib/Sema/SemaDeclObjC.cpp |4 + clang/lib/Sema/SemaObjCProperty.cpp |5 + clang/lib/Sema/SemaTemplate.cpp |7 + 10 files changed, 1045 insertions(+), 1 deletion(-) create mode 100644 clang/lib/Sema/SemaAPINotes.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ebda201361fb07..887d6120f48d2c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning< } // end of sema category +let CategoryName = "API Notes Issue" in { + +def err_incompatible_replacement_type : Error< + "API notes replacement type %0 has a different size from original type %1">; + +} // end of API Notes category + let CategoryName = "OpenMP Issue" in { // OpenMP support. def err_omp_expected_var_arg : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fcccac10f4733a..77749372b7fb65 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4883,6 +4883,12 @@ class Sema final { bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr , bool SkipArgCountCheck = false); + /// Map any API notes provided for this declaration to attributes on the + /// declaration. + /// + /// Triggered by declaration-attribute processing. + void ProcessAPINotes(Decl *D); + /// Determine if type T is a valid subject for a nonnull and similar /// attributes. By default, we look through references (the behavior used by /// nonnull), but if the second parameter is true, then we treat a reference diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 862f9d4ffb825d..e8bff07ced0cfa 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -27,6 +27,7 @@ add_clang_library(clangSema Sema.cpp SemaAccess.cpp SemaAttr.cpp + SemaAPINotes.cpp SemaAvailability.cpp SemaCXXScopeSpec.cpp SemaCast.cpp diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp new file mode 100644 index 00..f1b0b04391d756 --- /dev/null +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -0,0 +1,1003 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum class IsActive_t : bool { Inactive, Active }; +enum class IsReplacement_t : bool { Original, Replacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::Active), +IsReplacement(Replacement == IsReplacement_t::Replacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isIndirectPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/78445 >From 9e370f99cbee234efc37ec3bbb13b7bfbdcb67a4 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 17 Jan 2024 13:41:25 + Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../clang/Basic/DiagnosticSemaKinds.td|7 + clang/include/clang/Sema/Sema.h |6 + clang/lib/Sema/CMakeLists.txt |1 + clang/lib/Sema/SemaAPINotes.cpp | 1014 + clang/lib/Sema/SemaDecl.cpp |4 + clang/lib/Sema/SemaDeclAttr.cpp |3 + clang/lib/Sema/SemaDeclCXX.cpp|6 +- clang/lib/Sema/SemaDeclObjC.cpp |4 + clang/lib/Sema/SemaObjCProperty.cpp |5 + clang/lib/Sema/SemaTemplate.cpp |7 + 10 files changed, 1056 insertions(+), 1 deletion(-) create mode 100644 clang/lib/Sema/SemaAPINotes.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ebda201361fb07..887d6120f48d2c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning< } // end of sema category +let CategoryName = "API Notes Issue" in { + +def err_incompatible_replacement_type : Error< + "API notes replacement type %0 has a different size from original type %1">; + +} // end of API Notes category + let CategoryName = "OpenMP Issue" in { // OpenMP support. def err_omp_expected_var_arg : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fcccac10f4733a..77749372b7fb65 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4883,6 +4883,12 @@ class Sema final { bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr , bool SkipArgCountCheck = false); + /// Map any API notes provided for this declaration to attributes on the + /// declaration. + /// + /// Triggered by declaration-attribute processing. + void ProcessAPINotes(Decl *D); + /// Determine if type T is a valid subject for a nonnull and similar /// attributes. By default, we look through references (the behavior used by /// nonnull), but if the second parameter is true, then we treat a reference diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 862f9d4ffb825d..e8bff07ced0cfa 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -27,6 +27,7 @@ add_clang_library(clangSema Sema.cpp SemaAccess.cpp SemaAttr.cpp + SemaAPINotes.cpp SemaAvailability.cpp SemaCXXScopeSpec.cpp SemaCast.cpp diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp new file mode 100644 index 00..0a04a998918f6f --- /dev/null +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); compnerd wrote: Should this be `alignof(char)` or `alignof(char *)`? https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { compnerd wrote: ```suggestion static AttributeCommonInfo getPlaceholderAttrInfo() { ``` https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; compnerd wrote: How about converting this to a lambda and collapsing the subsequent cast and check? The `dyn_cast` is not exactly free and should simplify the code flow at the small cost of duplication of the call to the lambda. https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { compnerd wrote: How about `ASTAllocString` or `ASTDuplicateString`? https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; compnerd wrote: Could we get away with: ``` if (Type.isNull()) return; ``` https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; compnerd wrote: ```suggestion enum IsReplacement_t : bool { Original, Replacement }; ``` Similarly, consider `enum class`? https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); + } else if (auto Method = dyn_cast(D)) { +Method->setReturnType(Type); + +// Make it a context-sensitive keyword if we can. +if (!isMultiLevelPointerType(Type)) + Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( + Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); + + } else if (auto Value = dyn_cast(D)) { +Value->setType(Type); + +// Make it a context-sensitive keyword if we can. +if (auto Parm = dyn_cast(D)) { + if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type)) +Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( +Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); +} + } else if (auto Property = dyn_cast(D)) { +Property->setType(Type, Property->getTypeSourceInfo()); + +// Make it a property attribute if we can. +if (!isMultiLevelPointerType(Type)) + Property->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + + } else +llvm_unreachable("cannot handle nullability here"); +} + +/// Copy a string into ASTContext-allocated memory. +static StringRef CopyString(ASTContext , StringRef String) { + void *mem = Ctx.Allocate(String.size(), alignof(char)); + memcpy(mem, String.data(), String.size()); + return StringRef(static_cast(mem), String.size()); +} + +static AttributeCommonInfo getDummyAttrInfo() { + return AttributeCommonInfo(SourceRange(), + AttributeCommonInfo::UnknownAttribute, + {AttributeCommonInfo::AS_GNU, + /*Spelling*/ 0, /*IsAlignas*/ false, + /*IsRegularKeywordAttribute*/ false}); +} + +namespace { +template struct AttrKindFor {}; + +#define ATTR(X)
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static void applyNullability(Sema , Decl *D, NullabilityKind Nullability, + VersionedInfoMetadata Metadata) { + if (!Metadata.IsActive) +return; + + QualType Type; + + // Nullability for a function/method appertains to the retain type. + if (auto Function = dyn_cast(D)) +Type = Function->getReturnType(); + else if (auto Method = dyn_cast(D)) +Type = Method->getReturnType(); + else if (auto Value = dyn_cast(D)) +Type = Value->getType(); + else if (auto Property = dyn_cast(D)) +Type = Property->getType(); + else +return; + + // Check the nullability specifier on this type. + QualType OrigType = Type; + S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(), + isa(D), + /*overrideExisting=*/true); + if (Type.getTypePtr() == OrigType.getTypePtr()) +return; + + if (auto Function = dyn_cast(D)) { +const FunctionType *FnType = Function->getType()->castAs(); +if (const FunctionProtoType *Proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(), + Proto->getExtProtoInfo())); +else + Function->setType( + S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo())); compnerd wrote: Can we not use a QualType for the new type and then call `Function->setType` once? https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { compnerd wrote: Perhaps `IsIndirectPointer`? https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
@@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; compnerd wrote: ```suggestion enum IsActive_t : bool { Inactive, Active }; ``` Should we consider `enum class`? https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
egorzhdan wrote: @compnerd ping ;) https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
egorzhdan wrote: @compnerd ping! ;) https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
egorzhdan wrote: @compnerd ping :) https://github.com/llvm/llvm-project/pull/78445 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/78445 >From 6fdb42e20cc07a2f378239c6b7c6182e42544f18 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 17 Jan 2024 13:41:25 + Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../clang/Basic/DiagnosticSemaKinds.td|7 + clang/include/clang/Sema/Sema.h |6 + clang/lib/Sema/CMakeLists.txt |1 + clang/lib/Sema/SemaAPINotes.cpp | 1014 + clang/lib/Sema/SemaDecl.cpp |4 + clang/lib/Sema/SemaDeclAttr.cpp |3 + clang/lib/Sema/SemaDeclCXX.cpp|6 +- clang/lib/Sema/SemaDeclObjC.cpp |4 + clang/lib/Sema/SemaObjCProperty.cpp |5 + clang/lib/Sema/SemaTemplate.cpp |7 + 10 files changed, 1056 insertions(+), 1 deletion(-) create mode 100644 clang/lib/Sema/SemaAPINotes.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 03b0122d1c08f7..b705310dd37d6c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10723,6 +10723,13 @@ def warn_imp_cast_drops_unaligned : Warning< } // end of sema category +let CategoryName = "API Notes Issue" in { + +def err_incompatible_replacement_type : Error< + "API notes replacement type %0 has a different size from original type %1">; + +} // end of API Notes category + let CategoryName = "OpenMP Issue" in { // OpenMP support. def err_omp_expected_var_arg : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 2c0ad022bcf19d..f191f791741363 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4763,6 +4763,12 @@ class Sema final { bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr , bool SkipArgCountCheck = false); + /// Map any API notes provided for this declaration to attributes on the + /// declaration. + /// + /// Triggered by declaration-attribute processing. + void ProcessAPINotes(Decl *D); + /// Determine if type T is a valid subject for a nonnull and similar /// attributes. By default, we look through references (the behavior used by /// nonnull), but if the second parameter is true, then we treat a reference diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 1856a88e9a3271..4f72bce98fbbec 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -27,6 +27,7 @@ add_clang_library(clangSema Sema.cpp SemaAccess.cpp SemaAttr.cpp + SemaAPINotes.cpp SemaAvailability.cpp SemaCXXScopeSpec.cpp SemaCast.cpp diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp new file mode 100644 index 00..0a04a998918f6f --- /dev/null +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -0,0 +1,1014 @@ +//===--- SemaAPINotes.cpp - API Notes Handling ===// +// +// 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 implements the mapping from API notes to declaration attributes. +// +//===--===// + +#include "clang/APINotes/APINotesReader.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; + +namespace { +enum IsActive_t : bool { IsNotActive, IsActive }; +enum IsReplacement_t : bool { IsNotReplacement, IsReplacement }; + +struct VersionedInfoMetadata { + /// An empty version refers to unversioned metadata. + VersionTuple Version; + unsigned IsActive : 1; + unsigned IsReplacement : 1; + + VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, +IsReplacement_t Replacement) + : Version(Version), IsActive(Active == IsActive_t::IsActive), +IsReplacement(Replacement == IsReplacement_t::IsReplacement) {} +}; +} // end anonymous namespace + +/// Determine whether this is a multi-level pointer type. +static bool isMultiLevelPointerType(QualType Type) { + QualType Pointee = Type->getPointeeType(); + if (Pointee.isNull()) +return false; + + return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || + Pointee->isMemberPointerType(); +} + +/// Apply nullability to the given declaration. +static