-fanalyzer: Questions on C vs CPP + use of GCC attr's like malloc()/access()

2022-11-23 Thread Gavin Ray via Gcc
Hey all, just a few questions about the fantastic GCC Static Analyzer:

- It's stated that support for C++ vs C is very limited. Does this apply if
  you're writing C++ that is very similar-looking to C and uses few of C++'s
  advanced features?

- I noticed that in C++, the "gnu::malloc" attributes don't seem to report
  "warning: leak of 'xxx_alloc()' [CWE-401] [-Wanalyzer-malloc-leak]", is
this
  normal?

- Is it worthwhile to spend time annotating your method signatures with
  attributes like "malloc" and "access"? Do these aid the -fanalyzer passes?

For instance:

[[gnu::malloc]] [[gnu::malloc(HeapPage_free, 1)]] [[gnu::returns_nonnull]]
struct HeapPage* HeapPage_alloc();

[[gnu::access(read_write, 1, 3)]]
struct RecordID
HeapPage_insert_record(struct HeapPage* page, const char* record,
   uint32_t record_length);

That's quite a significant bit of annotation-noise tacked on to the
function, so
I wanted to be sure it's worth the investment!

Thank you =)
Gavin Ray


Re: -fanalyzer: Questions on C vs CPP + use of GCC attr's like malloc()/access()

2022-11-25 Thread Gavin Ray via Gcc
> Unfortunately not: even fairly simple-looking C++ code can generate extra CFG
edges relating to exception-handling ... making the output essentially useless.

Ahh, I had figured the answer might be something like this. Thanks for
confirming. At least from the small codebase I have, swapping from C -> C++ when
compiling preserves all -fanalyzer warnings except for the ones from custom
malloc() attributes, so that's nice.

I won't count on the analyzer being able to do a stellar job though, so I'll
take what I can get =)

> I'm hoping to spend a good chunk of the GCC 14 development cycle working on
> adding C++ support

That's awesome! I hope you'll write some on these changes again -- I really
enjoyed reading your article on the state of Static Analysis in GCC 12 and your
LPC presentation.

I believe that's where I learned about the SARIF exporter, which with the VS
Code extension is just beyond cool!

> The analyzer makes use of the "malloc", "nonnull" and "const" function
attributes. It does make use of the "access" attribute, but only within
-Wanalyzer- tainted-size, for the case where the size param of the access is
attacker-controlled.

Ahh okay, thanks. I currently don't run the taint analysis, as this app is a
database a-la Postgres/SQLite built as a learning exercise/hobby so it's not so
much of a concern.

> the first [[gnu::malloc]] here is redundant, as it's implied by
> [[gnu::malloc(HeapPage_free, 1)]].

Good to know, ty -- it may be useful to modify the 'attribute' docs for these,
because currently it shows combined usage and phrases it as:

"Independently, the form of the attribute with one or two arguments associates
deallocator as a suitable deallocation function..."

__attribute__ ((malloc, malloc (fclose, 1))) FILE* fdopen (int, const char*);

On a related note, the "fd" analyzers warn: "fd may not be valid" but don't
clarify what "valid" means.

I found the DOT diagrams in the analyzer source and it turns out that the key is
to check "if (fd >= 0)". Maybe this could be added to the "fd" analyzer
warnings/info, too?



Anyways, sorry to drone on. I think that the GCC Static Analyzer and the LLVM
Dataflow Analysis Framework are vital for the the evolution of safety and
developer experience in authoring C/C++

Big thanks to all involved and it's exciting to watch the shortlog & follow the
progress from the sidelines =)


Re: -fanalyzer: Questions on C vs CPP + use of GCC attr's like malloc()/access()

2022-11-26 Thread Gavin Ray via Gcc
I was using if (fd != -1) and was still getting the warning which confused me
My suggestion was maybe to add the exact condition the fd analyzer is
looking for to the warning so that folks know how to fix it/trigger
its 'true' branch.

e.g. instead of:
"fd may not be valid"

Something like this, or thereabouts:
"fd may not be valid (expecting fd >= 0)"

On Sat, Nov 26, 2022 at 9:09 AM Jonathan Wakely  wrote:
>
>
>
> On Fri, 25 Nov 2022, 18:55 Gavin Ray via Gcc,  wrote:
>>
>>
>> On a related note, the "fd" analyzers warn: "fd may not be valid" but don't
>> clarify what "valid" means.
>
>
> A valid file descriptor is one that was returned by the C library and refers 
> to an open file. That's not something GCC defines.
>
>>
>> I found the DOT diagrams in the analyzer source and it turns out that the 
>> key is
>> to check "if (fd >= 0)".
>
>
> The point is that the OS functions that return a new file descriptor return a 
> negative value on error, so all valid file descriptors are non-negative. But 
> not all non-negative integers are valid file descriptors.
>
> You should check for errors when calling open, dup2, socket etc. so you know 
> whether it succeeded.
>
>
>> Maybe this could be added to the "fd" analyzer
>> warnings/info, too?
>
>
> I don't think that's a good idea unless word carefully, it's not as simple as 
> "test if it's non-negative". You should check for errors when using OS APIs, 
> but that's always true, it's not difficult to the analyzer output.
>
>
>>
>>
>>
>>


Using [[may_alias]] in C23/C++23 on a union works in neither post-"union" position, or at the end of the definition

2022-12-05 Thread Gavin Ray via Gcc
The reproduction is below. Not sure if this is intended or a bug, sorry to
clutter up the mailing list if it's intended!

union __attribute__((may_alias)) works {};

// :3:18: note: attribute for 'union broken2' must follow the
'union' keyword
union broken1 {} [[may_alias]];

// Okay, so let's move it so it follows union...
// :7:21: warning: 'may_alias' attribute directive ignored
[-Wattributes]
//  7 | union [[may_alias]] broken2 {};
//| ^~~
union [[may_alias]] broken2 {};


Re: Using [[may_alias]] in C23/C++23 on a union works in neither post-"union" position, or at the end of the definition

2022-12-06 Thread Gavin Ray via Gcc
Oh, D'oh! Thanks Joseph, apologies for the needless email on the list then.

One final question if I could -- does that mean that in order to support
"may-alias" with the bracket syntax on both Clang and GCC, it would require:

 union [[gnu::may_alias]] [[clang::may_alias]] foo {};


On Tue, Dec 6, 2022 at 11:54 AM Joseph Myers 
wrote:

> On Mon, 5 Dec 2022, Gavin Ray via Gcc wrote:
>
> > union [[may_alias]] broken2 {};
>
> With [[]] syntax it's [[gnu::may_alias]], since it's not a standard
> attribute.
>
> --
> Joseph S. Myers
> jos...@codesourcery.com
>


Re: Using [[may_alias]] in C23/C++23 on a union works in neither post-"union" position, or at the end of the definition

2022-12-06 Thread Gavin Ray via Gcc
Ah got it, didn't know that (handy, will save me duplicating a bunch of
attributes).
Thanks Jonathan!

On Tue, Dec 6, 2022 at 2:23 PM Jonathan Wakely 
wrote:

>
>
> On Tue, 6 Dec 2022, 18:36 Gavin Ray via Gcc,  wrote:
>
>> Oh, D'oh! Thanks Joseph, apologies for the needless email on the list
>> then.
>>
>> One final question if I could -- does that mean that in order to support
>> "may-alias" with the bracket syntax on both Clang and GCC, it would
>> require:
>>
>>  union [[gnu::may_alias]] [[clang::may_alias]] foo {};
>>
>
>
>
> Probably not. Clang accepts the gnu:: namespace for attributes that
> originated with GCC.
>
>
>


Bug with GCC's handling of lifetimes of implicit-lifetime types

2022-12-10 Thread Gavin Ray via Gcc
This came up when I was asking around about what the proper way was to:

- Allocate aligned storage for a buffer pool/page cache
- Then create pointers to "Page" structs inside of the storage memory area

I thought something like this might do:

struct buffer_pool
{
  alignas(PAGE_SIZE) std::byte storage[NUM_PAGES * PAGE_SIZE];
  page* pages = new (storage) page[NUM_PAGES];
}

Someone told me that this was a valid solution but not to do it, because it
wouldn't function properly on GCC
They gave this as a reproduction:

https://godbolt.org/z/EhzM37Gzh

I'm not experienced enough with C++ to grok the connection between this
repro and my code, but I figured
I'd post it on the mailing list in case it was useful for others/might get
fixed in the future =)

They said it had to do with "handling of lifetimes of implicit-lifetime
types"


Re: Bug with GCC's handling of lifetimes of implicit-lifetime types

2022-12-10 Thread Gavin Ray via Gcc
Ahh alright, thanks Jonathan & Andrew, appreciate the replies

@Jonathan
> ... "Without a proper implementation of start_lifetime_as (which GCC
doesn't provide yet)"

I mailed the author of that proposal yesterday after learning about it
(it's very useful!) and they told me as much
Had written them to ask about a naive implementation I tried to see if I
understood it correctly:
- P2590R2: "Explicit lifetime management" (start_lifetime_as)
implementation (github.com)
<https://gist.github.com/GavinRay97/b69cb6ebab6a0e13d2cfe74a6ed7cdc6>


>
>
>
> *"Your code copies bytes around. The compiler *might* optimise that away
> but I'mnot sure. The idea of start_lifetime_as is that it would compile
> down to noinstructions - it would always be a no-op at runtime. My
> understanding is thatit cannot be implemented by the user in C++, the
> implementation would have to bea "magic" function using compiler
> intrinsics."*


About the memmove thing, based on a Godbolt link I found from Google -- I
think it's relying on UB to initialize storage + lifetime?
- Compiler Explorer (godbolt.org) <https://godbolt.org/z/VuRtNC>

But I don't pretend to understand the technicalities of the above, ha.

@Andrew

Would you be willing to attempt to explain the linked issue to someone not
familiar with the details of C++'s object storage + lifetime model?
Seems like an interesting thing but I don't have the technical
background/context to understand the full discussion happening there.






On Sat, Dec 10, 2022 at 1:44 PM Andrew Pinski  wrote:

> On Sat, Dec 10, 2022 at 10:36 AM Jonathan Wakely via Gcc
>  wrote:
> >
> > On Sat, 10 Dec 2022 at 17:42, Gavin Ray via Gcc  wrote:
> > >
> > > This came up when I was asking around about what the proper way was to:
> > >
> > > - Allocate aligned storage for a buffer pool/page cache
> > > - Then create pointers to "Page" structs inside of the storage memory
> area
> > >
> > > I thought something like this might do:
> > >
> > > struct buffer_pool
> > > {
> > >   alignas(PAGE_SIZE) std::byte storage[NUM_PAGES * PAGE_SIZE];
> > >   page* pages = new (storage) page[NUM_PAGES];
> > > }
> > >
> > > Someone told me that this was a valid solution but not to do it,
> because it
> > > wouldn't function properly on GCC
> > > They gave this as a reproduction:
> > >
> > > https://godbolt.org/z/EhzM37Gzh
> > >
> > > I'm not experienced enough with C++ to grok the connection between this
> > > repro and my code,
> >
> > Me neither. I don't think there is any connection, because I don't
> > think the repro shows what they think it shows.
> >
> > > but I figured
> > > I'd post it on the mailing list in case it was useful for others/might
> get
> > > fixed in the future =)
> > >
> > > They said it had to do with "handling of lifetimes of implicit-lifetime
> > > types"
> >
> > I don't think that code is a valid implementation of
> > start_lifetime_as. Without a proper implementation of
> > start_lifetime_as (which GCC doesn't provide yet), GCC does not allow
> > you to read the bytes of a float as an int, and doesn't give you the
> > bytes of 1.0f, it gives you 0.
> >
> > https://godbolt.org/z/dvncY9Pea works for GCC. But this has nothing to
> > do your code above, as far as I can see.
>
> See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107115#c10 for what
> is going wrong.
> Basically GCC does not have a way to express this in the IR currently
> and there are proposals there on how to do it.
>
> Thanks,
> Andrew Pinski
>


Re: Bug with GCC's handling of lifetimes of implicit-lifetime types

2022-12-11 Thread Gavin Ray via Gcc
@Richard

That's some intense code, I appreciate the code-samples and explanation,
thank you =)

@Jonathan

Maybe there was some misunderstanding?
I didn't make the connection either but I also don't know that much about
C++

It seems like that expression is valid then? Good to know =)

As a random aside if I may -- what is the difference between placement-new
of pointers in
std::byte storage, and making a std::span over the storage area?

std::byte storage[PAGE_SIZE * NUM_PAGES];

// A)
page* pages = new (storage) page[NUM_PAGES];
// B)
std::span pages_span(pages, NUM_PAGES);


On Sun, Dec 11, 2022 at 8:31 AM Richard Biener 
wrote:

> On Sun, Dec 11, 2022 at 1:02 PM Jonathan Wakely 
> wrote:
> >
> >
> >
> > On Sun, 11 Dec 2022, 09:12 Richard Biener, 
> wrote:
> >>
> >> On Sat, Dec 10, 2022 at 7:45 PM Andrew Pinski via Gcc 
> wrote:
> >> >
> >> > On Sat, Dec 10, 2022 at 10:36 AM Jonathan Wakely via Gcc
> >> >  wrote:
> >> > >
> >> > > On Sat, 10 Dec 2022 at 17:42, Gavin Ray via Gcc 
> wrote:
> >> > > >
> >> > > > This came up when I was asking around about what the proper way
> was to:
> >> > > >
> >> > > > - Allocate aligned storage for a buffer pool/page cache
> >> > > > - Then create pointers to "Page" structs inside of the storage
> memory area
> >> > > >
> >> > > > I thought something like this might do:
> >> > > >
> >> > > > struct buffer_pool
> >> > > > {
> >> > > >   alignas(PAGE_SIZE) std::byte storage[NUM_PAGES * PAGE_SIZE];
> >> > > >   page* pages = new (storage) page[NUM_PAGES];
> >> > > > }
> >> > > >
> >> > > > Someone told me that this was a valid solution but not to do it,
> because it
> >> > > > wouldn't function properly on GCC
> >> > > > They gave this as a reproduction:
> >> > > >
> >> > > > https://godbolt.org/z/EhzM37Gzh
> >> > > >
> >> > > > I'm not experienced enough with C++ to grok the connection
> between this
> >> > > > repro and my code,
> >> > >
> >> > > Me neither. I don't think there is any connection, because I don't
> >> > > think the repro shows what they think it shows.
> >> > >
> >> > > > but I figured
> >> > > > I'd post it on the mailing list in case it was useful for
> others/might get
> >> > > > fixed in the future =)
> >> > > >
> >> > > > They said it had to do with "handling of lifetimes of
> implicit-lifetime
> >> > > > types"
> >> > >
> >> > > I don't think that code is a valid implementation of
> >> > > start_lifetime_as. Without a proper implementation of
> >> > > start_lifetime_as (which GCC doesn't provide yet), GCC does not
> allow
> >> > > you to read the bytes of a float as an int, and doesn't give you the
> >> > > bytes of 1.0f, it gives you 0.
> >> > >
> >> > > https://godbolt.org/z/dvncY9Pea works for GCC. But this has
> nothing to
> >> > > do your code above, as far as I can see.
> >> >
> >> > See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107115#c10 for what
> >> > is going wrong.
> >> > Basically GCC does not have a way to express this in the IR currently
> >> > and there are proposals there on how to do it.
> >>
> >> I wouldn't call them "proposals" - basically the C++ language providing
> >> holes into the TBAA system is a misdesign, it will be incredibly
> difficult
> >> to implement this "hole" without sacrifying optimization which means
> >> people will complain endlessly why std::start_lifetime_as isn't a way
> >> to circumvent TBAA without losing optimization.
> >
> >
> > People already make holes in the type system, this just lets them do it
> without UB. If it's not as fast as their UB, that's ok IMHO.
> >
> >
> >
> > But I don't see what start_lifetime_as has to do with the original
> problem anyway. The placement new expression will start lifetimes:
> >
> > page* pages = new (storage) page[NUM_PAGES];
> >
> > There's no need to mess with the type system here.
>
> That's true, and that should work, not sure what the problem should be
> here.
>
> Richard.
>
> >
> >
>


Re: Bug with GCC's handling of lifetimes of implicit-lifetime types

2022-12-11 Thread Gavin Ray via Gcc
Whoops, the last line should be pages_span(storage, ...)

On Sun, Dec 11, 2022 at 8:38 AM Gavin Ray  wrote:

> @Richard
>
> That's some intense code, I appreciate the code-samples and explanation,
> thank you =)
>
> @Jonathan
>
> Maybe there was some misunderstanding?
> I didn't make the connection either but I also don't know that much about
> C++
>
> It seems like that expression is valid then? Good to know =)
>
> As a random aside if I may -- what is the difference between placement-new
> of pointers in
> std::byte storage, and making a std::span over the storage area?
>
> std::byte storage[PAGE_SIZE * NUM_PAGES];
>
> // A)
> page* pages = new (storage) page[NUM_PAGES];
> // B)
> std::span pages_span(pages, NUM_PAGES);
>
>
> On Sun, Dec 11, 2022 at 8:31 AM Richard Biener 
> wrote:
>
>> On Sun, Dec 11, 2022 at 1:02 PM Jonathan Wakely 
>> wrote:
>> >
>> >
>> >
>> > On Sun, 11 Dec 2022, 09:12 Richard Biener, 
>> wrote:
>> >>
>> >> On Sat, Dec 10, 2022 at 7:45 PM Andrew Pinski via Gcc 
>> wrote:
>> >> >
>> >> > On Sat, Dec 10, 2022 at 10:36 AM Jonathan Wakely via Gcc
>> >> >  wrote:
>> >> > >
>> >> > > On Sat, 10 Dec 2022 at 17:42, Gavin Ray via Gcc 
>> wrote:
>> >> > > >
>> >> > > > This came up when I was asking around about what the proper way
>> was to:
>> >> > > >
>> >> > > > - Allocate aligned storage for a buffer pool/page cache
>> >> > > > - Then create pointers to "Page" structs inside of the storage
>> memory area
>> >> > > >
>> >> > > > I thought something like this might do:
>> >> > > >
>> >> > > > struct buffer_pool
>> >> > > > {
>> >> > > >   alignas(PAGE_SIZE) std::byte storage[NUM_PAGES * PAGE_SIZE];
>> >> > > >   page* pages = new (storage) page[NUM_PAGES];
>> >> > > > }
>> >> > > >
>> >> > > > Someone told me that this was a valid solution but not to do it,
>> because it
>> >> > > > wouldn't function properly on GCC
>> >> > > > They gave this as a reproduction:
>> >> > > >
>> >> > > > https://godbolt.org/z/EhzM37Gzh
>> >> > > >
>> >> > > > I'm not experienced enough with C++ to grok the connection
>> between this
>> >> > > > repro and my code,
>> >> > >
>> >> > > Me neither. I don't think there is any connection, because I don't
>> >> > > think the repro shows what they think it shows.
>> >> > >
>> >> > > > but I figured
>> >> > > > I'd post it on the mailing list in case it was useful for
>> others/might get
>> >> > > > fixed in the future =)
>> >> > > >
>> >> > > > They said it had to do with "handling of lifetimes of
>> implicit-lifetime
>> >> > > > types"
>> >> > >
>> >> > > I don't think that code is a valid implementation of
>> >> > > start_lifetime_as. Without a proper implementation of
>> >> > > start_lifetime_as (which GCC doesn't provide yet), GCC does not
>> allow
>> >> > > you to read the bytes of a float as an int, and doesn't give you
>> the
>> >> > > bytes of 1.0f, it gives you 0.
>> >> > >
>> >> > > https://godbolt.org/z/dvncY9Pea works for GCC. But this has
>> nothing to
>> >> > > do your code above, as far as I can see.
>> >> >
>> >> > See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107115#c10 for what
>> >> > is going wrong.
>> >> > Basically GCC does not have a way to express this in the IR currently
>> >> > and there are proposals there on how to do it.
>> >>
>> >> I wouldn't call them "proposals" - basically the C++ language providing
>> >> holes into the TBAA system is a misdesign, it will be incredibly
>> difficult
>> >> to implement this "hole" without sacrifying optimization which means
>> >> people will complain endlessly why std::start_lifetime_as isn't a way
>> >> to circumvent TBAA without losing optimization.
>> >
>> >
>> > People already make holes in the type system, this just lets them do it
>> without UB. If it's not as fast as their UB, that's ok IMHO.
>> >
>> >
>> >
>> > But I don't see what start_lifetime_as has to do with the original
>> problem anyway. The placement new expression will start lifetimes:
>> >
>> > page* pages = new (storage) page[NUM_PAGES];
>> >
>> > There's no need to mess with the type system here.
>>
>> That's true, and that should work, not sure what the problem should be
>> here.
>>
>> Richard.
>>
>> >
>> >
>>
>


Re: Difficulty in implementing a GCC plugin for [[invariant]] contract functions in classes/structs without prior experience?

2022-12-29 Thread Gavin Ray via Gcc
So I have prototyped the code here, there are two places where I am
confused:
GCC [[invariant]] plugin for Design by Contract (WIP) (github.com)


1. Is it proper to cast like this?

tree args = NULL_TREE;
tree tmp_tree = NULL_TREE;
vec** args_ptr = (vec**)&args;

tree call = build_new_method_call(class_type, id, args_ptr, fun->decl,
LOOKUP_NORMAL, &tmp_tree, tf_warning_or_error);

2. At the bottom, I want to call "invariant()" before "return", but I'm not
sure how to phrase this in code. The following doesn't work quite right:
because you can't compare "gsi_stmt()" and NULL_TREE

// If the last block is a return block, insert the call before the
return statement.
if (gsi_stmt(gsi) != NULL_TREE && gimple_code(gsi_stmt(gsi)) ==
GIMPLE_RETURN)
gsi_insert_before(&gsi, g, GSI_SAME_STMT);
else
gsi_insert_after(&gsi, g, GSI_SAME_STMT);




On Thu, Dec 29, 2022 at 10:37 AM Gavin Ray  wrote:

> Hey all,
>
> The feature I appreciate most about the D programming language is its
> "Design by Contract" feature.
> Contract programming - Dlang Tour
> 
>
> With the recent merge of Contracts to GCC master, C++ comes close to this,
> with support for function-based contracts.
> The most powerful contract though, is the "invariant" contract:
>
> *invariant() is a special member function of struct and class types that
>> allows sanity checking an object's state during its whole lifetime:*
>
>
>>
>> *- invariant() is called after the constructor has run and before the
>> destructor is called.*
>> *- invariant() is called before entering a member function*
>> *- invariant() is called after exiting a member function.**- Class
>> invariants are inherited. That means that a derived class invariant will
>> implicitly call the base class invariant.*
>
>
> I'm very interested in prototyping a GCC plugin to implement support for
> transforming all member function calls in class/struct types
> such that a call to the [[invariant]]-annotated function (if any) is
> placed at the beginning and end of method bodies.
>
> Does anyone have any idea whether something like this would be suitable
> for a first plugin,
> or if there would be roadblocks/technical challenges to implementing such
> a thing?
>
> I'd be grateful for any advice.
>
> Thank you,
> Gavin =)
>
>


Re: Difficulty in implementing a GCC plugin for [[invariant]] contract functions in classes/structs without prior experience?

2022-12-30 Thread Gavin Ray via Gcc
Hey all, I've continued to work on this and have it mostly finished
The implementation is here

GCC [[invariant]] plugin for Design by Contract (WIP) (github.com)


I have posted the final remaining question to StackOverflow in case anyone
knows
It's about how to insert a call to a C++ Member Function, from another
Mem-Fn using the GIMPLE API:

GCC GIMPLE C++ API, how to insert a call to a member-function from another
member-function? - Stack Overflow


Would be grateful for any advice. I asked Iain Buclaw, who maintains GDC,
and he was able to help but doesn't have a ton of expertise in the C++
frontend.
Thanks all

On Thu, Dec 29, 2022 at 1:33 PM Gavin Ray  wrote:

> So I have prototyped the code here, there are two places where I am
> confused:
> GCC [[invariant]] plugin for Design by Contract (WIP) (github.com)
> 
>
> 1. Is it proper to cast like this?
>
> tree args = NULL_TREE;
> tree tmp_tree = NULL_TREE;
> vec** args_ptr = (vec**)&args;
>
> tree call = build_new_method_call(class_type, id, args_ptr, fun->decl,
> LOOKUP_NORMAL, &tmp_tree, tf_warning_or_error);
>
> 2. At the bottom, I want to call "invariant()" before "return", but I'm
> not sure how to phrase this in code. The following doesn't work quite right:
> because you can't compare "gsi_stmt()" and NULL_TREE
>
> // If the last block is a return block, insert the call before the
> return statement.
> if (gsi_stmt(gsi) != NULL_TREE && gimple_code(gsi_stmt(gsi)) ==
> GIMPLE_RETURN)
> gsi_insert_before(&gsi, g, GSI_SAME_STMT);
> else
> gsi_insert_after(&gsi, g, GSI_SAME_STMT);
>
>
>
>
> On Thu, Dec 29, 2022 at 10:37 AM Gavin Ray  wrote:
>
>> Hey all,
>>
>> The feature I appreciate most about the D programming language is its
>> "Design by Contract" feature.
>> Contract programming - Dlang Tour
>> 
>>
>> With the recent merge of Contracts to GCC master, C++ comes close to
>> this, with support for function-based contracts.
>> The most powerful contract though, is the "invariant" contract:
>>
>> *invariant() is a special member function of struct and class types that
>>> allows sanity checking an object's state during its whole lifetime:*
>>
>>
>>>
>>> *- invariant() is called after the constructor has run and before the
>>> destructor is called.*
>>> *- invariant() is called before entering a member function*
>>> *- invariant() is called after exiting a member function.**- Class
>>> invariants are inherited. That means that a derived class invariant will
>>> implicitly call the base class invariant.*
>>
>>
>> I'm very interested in prototyping a GCC plugin to implement support for
>> transforming all member function calls in class/struct types
>> such that a call to the [[invariant]]-annotated function (if any) is
>> placed at the beginning and end of method bodies.
>>
>> Does anyone have any idea whether something like this would be suitable
>> for a first plugin,
>> or if there would be roadblocks/technical challenges to implementing such
>> a thing?
>>
>> I'd be grateful for any advice.
>>
>> Thank you,
>> Gavin =)
>>
>>