Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add more compilation flags #258

Merged

Conversation

slaperche-scality
Copy link
Contributor

In order to keep a good level of code quality, this PR introduces makes Clang and GCC stricter.

The set of flags are the ones that were used on the DCSS project.

The next step will be to enable more lint check in clang-tidy, but that PR is already big enough as it is.

Also, before moving onto the linter, there are still two more warnings that I want to enable: -Wconversion and -Wshadow.
Those will require a litlte bit more rework so they will be done in a dedicated PR:

  • -Wconversion: it's probably wise to tackle Indices should be declared as size_t #243 first
  • -Wshadow will require a bit of wide renaming (but in the end will improve the code readability) and I'll probably rework the visibility of some fields on the way (too many public fields in some of our classes right now).

@slaperche-scality
Copy link
Contributor Author

@lamphamsy It would be great if you could review the changes in the commit "fix Doxygen documentation (flagged by -Wdocumentation)" carefully.

Most of the errors flagged by -Wdocumentation were about missing description for function parameters.
I fixed those by either:

  • adding a description when I clearly understood what's the role of the parameter
  • adding a not-so-useful-but-not-wrong description when it wasn't clear to me
  • removing the documentation of the parameters

If you have suggestions for those, I would be more than happy to update this commit with better descriptions/documentation 🙂

@slaperche-scality slaperche-scality force-pushed the eh/add_compiler_warnings branch 4 times, most recently from 2348531 to 4dfa7b2 Compare October 22, 2018 08:50
Type qualifiers (such as const) are ignored on function return type.
Add missing noreturn attribute.
`narrow_cast` is a simple wrapper around `static_cast` and should be
used when you cast to narrow a value.

That way, if one day we have a bug related to narrowing, we can simply
grep for the specific `narrow_cast` instead of the more general
`static_cast`.
Don't use C-like cast, C++ offers a wider range of cast, each own with
its own semantic and rules.
Note the most of the occurences are fixed by replacing some pure virtual
methods by virtual methods with a default body that does nothing (as
most of the children classes were doing nothing…).

Also remove a truly unused parameter from `unpack`.
Either add missing prototypes or mark the function with static.
Here is a quick drill down, for those unfamiliar with this aspect of
C++.

What's is this about?
=====================

The first thing to note is that there is no overloading across scopes,
and derived class scopes are not an exception.

Concretely, that means that this code:

    struct A {
        int foo(int i) { std::cout << "foo(int): "; return i+1; }
    };

    struct B : public A {
        double f(double d) { std::cout << "foo(double): "; return d+1.3; }
    };
    […]
    B* pd = new B;
    std::cout << pb->f(2) << '\n';

Will produce:

    f(double): 3.3

Because the best method is only looked up into D scope, so even though a
better match is available for `int` in B, it's not found and the version
for `double` is used.

The compiler warning is triggered when the hidden function is virtual,
as shown in the example from the man:

    struct A {
        virtual void f();
    };

    struct B: public A {
        void f(int);
    };

the A class version of f is hidden in B, and code like:

    B* b;
    b->f();

fails to compile.

What about us?
==============

Our codebase is affected by this problem, the hidden functions are:
- void FecCode<T>::decode_apply(const DecodeContext<T>&, Buffers<T>&, Buffers<T>&)
- void FecCode<T>::decode_prepare(const DecodeContext<T>&, const std::vector<Properties>&, off_t, Buffers<T>&)
- void FecCode<T>::encode_post_process(Buffers<T>&, std::vector<Properties>&, off_t)
- void FecCode<T>::encode(Buffers<T>&, std::vector<quadiron::Properties>&, off_t, Buffers<T>&)
- void FourierTransform<T>::fft_inv(Buffers<T>&, Buffers<T>&)
- void FourierTransform<T>::fft(Buffers<T>&, Buffers<T>&)
- void FourierTransform<T>::ifft(Buffers<T>&, Buffers<T>&)
- void RingModN<T>::neg(Buffers<T>&) const
- void RingModN<T>::neg(size_t, T*) const

You can see that most of them are `Buffers` version of pure abtract
methods that works on `Vector`.

Since the `Vector` versions are pure abstract, children classes must
override them and by doing so mask the overloaded versions that work on
`Buffers` (except if they also override the `Buffers` versions`, but
that's not always the case).

Example:
- `fft::Radix2` override both `Vector` and `Buffers` versions
  => no compiler warning.
- `fft::CooleyTukey` doesn't override the `Buffers` versions
  => we have a warning.

But our code compile/works!
===========================

Yeah, by happenstance.

Because most of these `Buffers` version are defined as no-op by default
and if a child class doesn't override it that propably means that it's
never called and thus yeah, our code compile.

But that doesn't change the fact that the code is brittle, and we should
clean these up!

How do we fix this?
===================

By explicitely asking for the methods lookup to consider the scope of
the parent class, which is done with an using-declaration.

Appendix: why this weird and confusing behavior‽
================================================

Because if we were looking up into the parents' scopes, then the code
have certain unforeseen and potentially dangerous behavior.

Consider the following code:

    class Base {
        int x;
    public:
        virtual void copy(Base* p) { x = p-> x; }
    };

    class Derived{
        int xx;
    public:
        virtual void copy(Derived* p) { xx = p->xx; Base::copy(p); }
    };

    void f(Base a, Derived b)
    {
        a.copy(&b); // ok: copy Base part of b
        b.copy(&a); // BUG: Base::copy is called and `xx` is not copied!
    }

If we were looking up into the parent's scope, then we would find
`Base::copy(Base*)` which is a better match for the second call to copy
BUT it would lead to object slicing, which is unexpected here!

References
==========

- http://www.stroustrup.com/bs_faq2.html#overloadderived
- https://stackoverflow.com/a/1629074
VLA are not supported in C++, that's a C99 feature not a C++ one (and
even in C, it becames optional since C11).

Even if they were supported, it's not a good idea to use them
(especially with an unbounded size such as `this->n`) this is a recipe
for easy stack overflows.

Now, dumbly replacing VLAs by `std::vector` simply won't do (the code
becomes 50% slower). But, we can implement a scratch space inside the
`gf::NF4` object that can replaces the VLAs and get a nice 10% speedup :)
`typename` is preferred in this context, and this is what we use in the
rest of the codebase.
Copy link
Contributor

@lamphamsy lamphamsy left a comment

Choose a reason for hiding this comment

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

Great Cleanup. Thanks

src/arith.h Outdated Show resolved Hide resolved
src/arith.h Outdated Show resolved Hide resolved
src/arith.h Outdated Show resolved Hide resolved
src/arith.h Outdated Show resolved Hide resolved
src/fec_base.h Outdated Show resolved Hide resolved
src/fft_add.h Outdated Show resolved Hide resolved
src/gf_ring.h Outdated Show resolved Hide resolved
src/gf_ring.h Outdated Show resolved Hide resolved
src/vec_vector.h Show resolved Hide resolved
src/gf_nf4.h Show resolved Hide resolved
Since we have a destructor, we add:
- a copy constructor
- a move constructor
- a copy assignment operator
- a move assignment operator

Clang was complaining about it (`-Wdeprecated`), and rightly so!

    definition of implicit copy constructor for 'Vector<unsigned int>'
    is deprecated because it has a user-declared destructor
This will definitely help us spot dubious code and maintain a good level
of code quality.

Next step would be to enable more lint in clang-tidy.
The debug mode is the one with the more warnings, so this is the one
that should be tested (if it compiles in Debug, it will compile in
Release), but since we use conditionnal compilation for SIMD we should
make sure that every codepath is clean.

Compilation in all SIMD mode in release is done by the test job anyway.
We should use list append, not string concat to add the SIMD flag.
`k` is a member variable and is ambiguous with local variable (such as
in `taylor_expand_t2`).

A more global renaming is planned later, when we will add `-Wshadow` to
our compilation flags.
Copy link
Contributor Author

@slaperche-scality slaperche-scality left a comment

Choose a reason for hiding this comment

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

Thank you for the detailed review!

src/arith.h Outdated Show resolved Hide resolved
src/arith.h Outdated Show resolved Hide resolved
src/arith.h Outdated Show resolved Hide resolved
src/arith.h Outdated Show resolved Hide resolved
src/fec_base.h Outdated Show resolved Hide resolved
src/fft_add.h Outdated Show resolved Hide resolved
src/gf_ring.h Outdated Show resolved Hide resolved
src/gf_ring.h Outdated Show resolved Hide resolved
src/vec_vector.h Show resolved Hide resolved
src/gf_nf4.h Show resolved Hide resolved
@slaperche-scality slaperche-scality merged commit 988f9e8 into scality:master Nov 1, 2018
@slaperche-scality slaperche-scality deleted the eh/add_compiler_warnings branch November 1, 2018 04:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants