[MS] Add frontend support for __declspec(allocator)

The intention is to add metadata to direct call sites of functions
marked with __declspec(allocator), which will ultimately result in some
S_HEAPALLOCSITE debug info records when emitting codeview.

This is a piece of PR38491

llvm-svn: 356964
This commit is contained in:
Reid Kleckner 2019-03-25 23:20:18 +00:00
parent 1e5d569c8c
commit 1181c9f45d
5 changed files with 57 additions and 0 deletions

View File

@ -2757,6 +2757,12 @@ def : IgnoredAttr {
let Spellings = [Declspec<"property">];
}
def MSAllocator : InheritableAttr {
let Spellings = [Declspec<"allocator">];
let Subjects = SubjectList<[Function]>;
let Documentation = [MSAllocatorDocs];
}
def MSStruct : InheritableAttr {
let Spellings = [GCC<"ms_struct">];
let Subjects = SubjectList<[Record]>;

View File

@ -4089,3 +4089,20 @@ it will be automatically applied to overrides if the method is virtual. The
attribute can also be written using C++11 syntax: ``[[mig::server_routine]]``.
}];
}
def MSAllocatorDocs : Documentation {
let Category = DocCatType;
let Content = [{
The ``__declspec(allocator)`` attribute is applied to functions that allocate
memory, such as operator new in C++. When CodeView debug information is emitted
(enabled by ``clang -gcodeview`` or ``clang-cl /Z7``), Clang will attempt to
record the code offset of heap allocation call sites in the debug info. It will
also record the type being allocated using some local heuristics. The Visual
Studio debugger uses this information to `profile memory usage`_.
.. _profile memory usage: https://docs.microsoft.com/en-us/visualstudio/profiling/memory-usage
This attribute does not affect optimizations in any way, unlike GCC's
``__attribute__((malloc))``.
}];
}

View File

@ -2956,6 +2956,9 @@ def err_base_specifier_attribute : Error<
"%0 attribute cannot be applied to a base specifier">;
def err_invalid_attribute_on_virtual_function : Error<
"%0 attribute cannot be applied to virtual functions">;
def warn_declspec_allocator_nonpointer : Warning<
"ignoring __declspec(allocator) because the function return type %0 is not "
"a pointer or reference type">, InGroup<IgnoredAttributes>;
def ext_cannot_use_trivial_abi : ExtWarn<
"'trivial_abi' cannot be applied to %0">, InGroup<IgnoredAttributes>;

View File

@ -6548,6 +6548,20 @@ static void handleMIGServerRoutineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
handleSimpleAttribute<MIGServerRoutineAttr>(S, D, AL);
}
static void handleMSAllocatorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Warn if the return type is not a pointer or reference type.
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
QualType RetTy = FD->getReturnType();
if (!RetTy->isPointerType() && !RetTy->isReferenceType()) {
S.Diag(AL.getLoc(), diag::warn_declspec_allocator_nonpointer)
<< AL.getRange() << RetTy;
return;
}
}
handleSimpleAttribute<MSAllocatorAttr>(S, D, AL);
}
//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
@ -7281,6 +7295,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_MIGServerRoutine:
handleMIGServerRoutineAttr(S, D, AL);
break;
case ParsedAttr::AT_MSAllocator:
handleMSAllocatorAttr(S, D, AL);
break;
}
}

View File

@ -0,0 +1,13 @@
// RUN: %clang_cc1 -fms-compatibility -triple x86_64-windows-msvc -std=c++14 -fms-extensions -fms-compatibility-version=19.00 -verify %s
__declspec(allocator) int err_on_data; // expected-warning {{'allocator' attribute only applies to functions}}
__declspec(allocator) struct ErrOnStruct1; // expected-warning {{place it after "struct" to apply attribute}}
struct __declspec(allocator) ErrOnStruct2 {}; // expected-warning {{'allocator' attribute only applies to functions}}
__declspec(allocator) void err_on_ret_void(); // expected-warning {{not a pointer or reference type}}
__declspec(allocator) int err_on_ret_int(); // expected-warning {{not a pointer or reference type}}
__declspec(allocator) void *accept_on_ptr1();
__declspec(allocator) void *accept_on_ptr2(size_t);
void * __declspec(allocator) accept_on_ptr3(size_t); // expected-error {{expected unqualified-id}}
struct Foo { int x; };
__declspec(allocator) Foo *accept_nonvoid_ptr(size_t);