Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions clang/include/clang/APINotes/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -445,19 +445,16 @@ class ParamInfo : public VariableInfo {
RawRetainCountConvention() {}

std::optional<bool> isNoEscape() const {
if (!NoEscapeSpecified)
return std::nullopt;
return NoEscape;
return NoEscapeSpecified ? std::optional<bool>(NoEscape) : std::nullopt;
}
void setNoEscape(std::optional<bool> Value) {
NoEscapeSpecified = Value.has_value();
NoEscape = Value.value_or(false);
}

std::optional<bool> isLifetimebound() const {
if (!LifetimeboundSpecified)
return std::nullopt;
return Lifetimebound;
return LifetimeboundSpecified ? std::optional<bool>(Lifetimebound)
: std::nullopt;
}
void setLifetimebound(std::optional<bool> Value) {
LifetimeboundSpecified = Value.has_value();
Expand Down Expand Up @@ -643,6 +640,8 @@ class ObjCMethodInfo : public FunctionInfo {
LLVM_PREFERRED_TYPE(bool)
unsigned RequiredInit : 1;

std::optional<ParamInfo> Self;

ObjCMethodInfo() : DesignatedInit(false), RequiredInit(false) {}

friend bool operator==(const ObjCMethodInfo &, const ObjCMethodInfo &);
Expand All @@ -664,7 +663,7 @@ class ObjCMethodInfo : public FunctionInfo {
inline bool operator==(const ObjCMethodInfo &LHS, const ObjCMethodInfo &RHS) {
return static_cast<const FunctionInfo &>(LHS) == RHS &&
LHS.DesignatedInit == RHS.DesignatedInit &&
LHS.RequiredInit == RHS.RequiredInit;
LHS.RequiredInit == RHS.RequiredInit && LHS.Self == RHS.Self;
}

inline bool operator!=(const ObjCMethodInfo &LHS, const ObjCMethodInfo &RHS) {
Expand Down Expand Up @@ -693,8 +692,20 @@ class FieldInfo : public VariableInfo {
class CXXMethodInfo : public FunctionInfo {
public:
CXXMethodInfo() {}

std::optional<ParamInfo> This;

LLVM_DUMP_METHOD void dump(llvm::raw_ostream &OS);
};

inline bool operator==(const CXXMethodInfo &LHS, const CXXMethodInfo &RHS) {
return static_cast<const FunctionInfo &>(LHS) == RHS && LHS.This == RHS.This;
}

inline bool operator!=(const CXXMethodInfo &LHS, const CXXMethodInfo &RHS) {
return !(LHS == RHS);
}

/// Describes API notes data for an enumerator.
class EnumConstantInfo : public CommonEntityInfo {
public:
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/APINotes/APINotesFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ const uint16_t VERSION_MAJOR = 0;
/// API notes file minor version number.
///
/// When the format changes IN ANY WAY, this number should be incremented.
const uint16_t VERSION_MINOR = 31; // lifetimebound
const uint16_t VERSION_MINOR =
32; // implicit parameter support (at position -1)

const uint8_t kSwiftCopyable = 1;
const uint8_t kSwiftNonCopyable = 2;
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/APINotes/APINotesReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "clang/APINotes/APINotesReader.h"
#include "APINotesFormat.h"
#include "clang/APINotes/Types.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitstream/BitstreamReader.h"
Expand Down Expand Up @@ -396,12 +397,19 @@ class ObjCMethodTableInfo
const uint8_t *&Data) {
ObjCMethodInfo Info;
uint8_t Payload = *Data++;
bool HasSelf = Payload & 0x01;
Payload >>= 1;
Info.RequiredInit = Payload & 0x01;
Payload >>= 1;
Info.DesignatedInit = Payload & 0x01;
Payload >>= 1;
assert(Payload == 0 && "Unable to fully decode 'Payload'.");

ReadFunctionInfo(Data, Info);
if (HasSelf) {
Info.Self = ParamInfo{};
ReadParamInfo(Data, *Info.Self);
}
return Info;
}
};
Expand Down Expand Up @@ -516,7 +524,17 @@ class CXXMethodTableInfo
static CXXMethodInfo readUnversioned(internal_key_type Key,
const uint8_t *&Data) {
CXXMethodInfo Info;

uint8_t Payload = *Data++;
bool HasThis = Payload & 0x01;
Payload >>= 1;
assert(Payload == 0 && "Unable to fully decode 'Payload'.");

ReadFunctionInfo(Data, Info);
if (HasThis) {
Info.This = ParamInfo{};
ReadParamInfo(Data, *Info.This);
}
return Info;
}
};
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/APINotes/APINotesTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,18 @@ LLVM_DUMP_METHOD void FunctionInfo::dump(llvm::raw_ostream &OS) const {

LLVM_DUMP_METHOD void ObjCMethodInfo::dump(llvm::raw_ostream &OS) {
static_cast<FunctionInfo &>(*this).dump(OS);
if (Self)
Self->dump(OS);
OS << (DesignatedInit ? "[DesignatedInit] " : "")
<< (RequiredInit ? "[RequiredInit] " : "") << '\n';
}

LLVM_DUMP_METHOD void CXXMethodInfo::dump(llvm::raw_ostream &OS) {
static_cast<FunctionInfo &>(*this).dump(OS);
if (This)
This->dump(OS);
}

LLVM_DUMP_METHOD void TagInfo::dump(llvm::raw_ostream &OS) {
static_cast<CommonTypeInfo &>(*this).dump(OS);
if (HasFlagEnum)
Expand Down
29 changes: 24 additions & 5 deletions clang/lib/APINotes/APINotesWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@ namespace {
unsigned getVariableInfoSize(const VariableInfo &VI) {
return 2 + getCommonEntityInfoSize(VI) + 2 + VI.getType().size();
}
unsigned getParamInfoSize(const ParamInfo &PI);

/// Emit a serialized representation of the variable information.
void emitVariableInfo(raw_ostream &OS, const VariableInfo &VI) {
Expand Down Expand Up @@ -737,6 +738,7 @@ void APINotesWriter::Implementation::writeObjCPropertyBlock(
namespace {
unsigned getFunctionInfoSize(const FunctionInfo &);
void emitFunctionInfo(llvm::raw_ostream &, const FunctionInfo &);
void emitParamInfo(raw_ostream &OS, const ParamInfo &PI);

/// Used to serialize the on-disk Objective-C method table.
class ObjCMethodTableInfo
Expand All @@ -760,17 +762,24 @@ class ObjCMethodTableInfo
}

unsigned getUnversionedInfoSize(const ObjCMethodInfo &OMI) {
return getFunctionInfoSize(OMI) + 1;
auto size = getFunctionInfoSize(OMI) + 1;
if (OMI.Self)
size += getParamInfoSize(*OMI.Self);
return size;
}

void emitUnversionedInfo(raw_ostream &OS, const ObjCMethodInfo &OMI) {
uint8_t flags = 0;
llvm::support::endian::Writer writer(OS, llvm::endianness::little);
flags = (flags << 1) | OMI.DesignatedInit;
flags = (flags << 1) | OMI.RequiredInit;
flags = (flags << 1) | static_cast<bool>(OMI.Self);
writer.write<uint8_t>(flags);

emitFunctionInfo(OS, OMI);

if (OMI.Self)
emitParamInfo(OS, *OMI.Self);
}
};

Expand All @@ -793,12 +802,22 @@ class CXXMethodTableInfo
return static_cast<size_t>(key.hashValue());
}

unsigned getUnversionedInfoSize(const CXXMethodInfo &OMI) {
return getFunctionInfoSize(OMI);
unsigned getUnversionedInfoSize(const CXXMethodInfo &MI) {
auto size = getFunctionInfoSize(MI) + 1;
if (MI.This)
size += getParamInfoSize(*MI.This);
return size;
}

void emitUnversionedInfo(raw_ostream &OS, const CXXMethodInfo &OMI) {
emitFunctionInfo(OS, OMI);
void emitUnversionedInfo(raw_ostream &OS, const CXXMethodInfo &MI) {
uint8_t flags = 0;
llvm::support::endian::Writer writer(OS, llvm::endianness::little);
flags = (flags << 1) | static_cast<bool>(MI.This);
writer.write<uint8_t>(flags);

emitFunctionInfo(OS, MI);
if (MI.This)
emitParamInfo(OS, *MI.This);
}
};
} // namespace
Expand Down
28 changes: 21 additions & 7 deletions clang/lib/APINotes/APINotesYAMLCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "llvm/Support/VersionTuple.h"
#include "llvm/Support/YAMLTraits.h"
#include <optional>
#include <type_traits>
#include <vector>

using namespace clang;
Expand Down Expand Up @@ -68,7 +69,7 @@ template <> struct ScalarEnumerationTraits<MethodKind> {

namespace {
struct Param {
unsigned Position;
int Position;
std::optional<bool> NoEscape = false;
std::optional<bool> Lifetimebound = false;
std::optional<NullabilityKind> Nullability;
Expand Down Expand Up @@ -730,7 +731,8 @@ class YAMLConverter {
}
}

void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) {
void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo,
std::optional<ParamInfo> &thisOrSelf) {
for (const auto &P : Params) {
ParamInfo PI;
if (P.Nullability)
Expand All @@ -739,9 +741,14 @@ class YAMLConverter {
PI.setLifetimebound(P.Lifetimebound);
PI.setType(std::string(P.Type));
PI.setRetainCountConvention(P.RetainCountConvention);
if (OutInfo.Params.size() <= P.Position)
if (static_cast<int>(OutInfo.Params.size()) <= P.Position)
OutInfo.Params.resize(P.Position + 1);
OutInfo.Params[P.Position] |= PI;
if (P.Position == -1)
thisOrSelf = PI;
else if (P.Position >= 0)
OutInfo.Params[P.Position] |= PI;
else
emitError("invalid parameter position " + llvm::itostr(P.Position));
}
}

Expand Down Expand Up @@ -818,7 +825,7 @@ class YAMLConverter {
MI.ResultType = std::string(M.ResultType);

// Translate parameter information.
convertParams(M.Params, MI);
convertParams(M.Params, MI, MI.Self);

// Translate nullability info.
convertNullability(M.Nullability, M.NullabilityOfRet, MI, M.Selector);
Expand Down Expand Up @@ -926,11 +933,18 @@ class YAMLConverter {
TheNamespace.Items, SwiftVersion);
}

void convertFunction(const Function &Function, FunctionInfo &FI) {
template <typename FuncOrMethodInfo>
void convertFunction(const Function &Function, FuncOrMethodInfo &FI) {
convertAvailability(Function.Availability, FI, Function.Name);
FI.setSwiftPrivate(Function.SwiftPrivate);
FI.SwiftName = std::string(Function.SwiftName);
convertParams(Function.Params, FI);
std::optional<ParamInfo> This;
convertParams(Function.Params, FI, This);
if constexpr (std::is_same_v<FuncOrMethodInfo, CXXMethodInfo>)
FI.This = This;
else if (This)
emitError("implicit instance parameter is only permitted on C++ and "
"Objective-C methods");
convertNullability(Function.Nullability, Function.NullabilityOfRet, FI,
Function.Name);
FI.ResultType = std::string(Function.ResultType);
Expand Down
16 changes: 16 additions & 0 deletions clang/lib/Sema/SemaAPINotes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
//
//===----------------------------------------------------------------------===//

#include "TypeLocBuilder.h"
#include "clang/APINotes/APINotesReader.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Lex/Lexer.h"
#include "clang/Sema/SemaInternal.h"
Expand Down Expand Up @@ -567,6 +569,20 @@ static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc,
static void ProcessAPINotes(Sema &S, CXXMethodDecl *Method,
const api_notes::CXXMethodInfo &Info,
VersionedInfoMetadata Metadata) {
if (Info.This && Info.This->isLifetimebound()) {
auto MethodType = Method->getType();
auto *attr = ::new (S.Context)
LifetimeBoundAttr(S.Context, getPlaceholderAttrInfo());
QualType AttributedType =
S.Context.getAttributedType(attr, MethodType, MethodType);
TypeLocBuilder TLB;
TLB.pushFullCopy(Method->getTypeSourceInfo()->getTypeLoc());
AttributedTypeLoc TyLoc = TLB.push<AttributedTypeLoc>(AttributedType);
TyLoc.setAttr(attr);
Method->setType(AttributedType);
Method->setTypeSourceInfo(TLB.getTypeSourceInfo(S.Context, AttributedType));
}

ProcessAPINotes(S, (FunctionOrMethod)Method, Info, Metadata);
}

Expand Down
4 changes: 4 additions & 0 deletions clang/test/APINotes/Inputs/Headers/Lifetimebound.apinotes
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Functions:
Tags:
- Name: MyClass
Methods:
- Name: annotateThis
Parameters:
- Position: -1
Lifetimebound: true
- Name: methodToAnnotate
Parameters:
- Position: 0
Expand Down
1 change: 0 additions & 1 deletion clang/test/APINotes/Inputs/Headers/Lifetimebound.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
int *funcToAnnotate(int *p);

// TODO: support annotating ctors and 'this'.
struct MyClass {
MyClass(int*);
int *annotateThis();
Expand Down
3 changes: 3 additions & 0 deletions clang/test/APINotes/lifetimebound.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Lifetimebound -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers %s -x c++
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Lifetimebound -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter funcToAnnotate -x c++ | FileCheck --check-prefix=CHECK-PARAM %s
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Lifetimebound -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter annotateThis -x c++ | FileCheck --check-prefix=CHECK-METHOD-THIS %s
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Lifetimebound -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter methodToAnnotate -x c++ | FileCheck --check-prefix=CHECK-METHOD %s
#include "Lifetimebound.h"

Expand All @@ -11,3 +12,5 @@
// CHECK-METHOD: CXXMethodDecl {{.+}} methodToAnnotate
// CHECK-METHOD-NEXT: ParmVarDecl {{.+}} p
// CHECK-METHOD-NEXT: LifetimeBoundAttr

// CHECK-METHOD-THIS: CXXMethodDecl {{.+}} annotateThis 'int *() {{\[\[}}clang::lifetimebound{{\]\]}}'
Loading