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

fix GetVariableOffset in cases of multi-level and multiple inheritance #396

Merged

Conversation

Vipul-Cariappa
Copy link
Collaborator

Description

Fixes the calculation of data member offsets of a class C. Where C inherits from multiple classes and these classes themselves inherit from other classes.

Fixes # (issue)

I found this issue when tinkering with cross-inheritance in cppyy.
It looks like upstream cppyy also faces a similar problem. Opened a PR stating the issue at wlav/cppyy#280.

Does not contribute to test cases that pass in cppyy.

Type of change

Please tick all options which are relevant.

  • Bug fix
  • New feature
  • Requires documentation updates

Testing

Added in tests with multi-level and multiple inheritance.

Checklist

  • I have read the contribution guide recently

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 10 out of 19. Check the log or trigger a new build to see more.

lib/Interpreter/CppInterOp.cpp Show resolved Hide resolved
lib/Interpreter/CppInterOp.cpp Outdated Show resolved Hide resolved
: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: parameter 'b' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:270: expanded from macro 'CODE'

    BaseB(int x, std::string b) : BaseA(x), b(b) {}                            \
                                              ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: parameter 's' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:277: expanded from macro 'CODE'

    Base1(int i, std::string s) : i(i), s(s) {}                                \
                                          ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: pass by value and use std::move [modernize-pass-by-value]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:270: expanded from macro 'CODE'

    BaseB(int x, std::string b) : BaseA(x), b(b) {}                            \
                 ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: variable 'my_k' is non-const and globally accessible, consider making it const [cppcoreguidelines-avoid-non-const-global-variables]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:285: expanded from macro 'CODE'

  } my_k(5, 4, 3, "Cpp", "Python");
    ^

TEST(VariableReflectionTest, VariableOffsetsWithInheritance) {
Cpp::Declare("#include<string>");

#define Stringify(s) Stringifyx(s)
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: function-like macro 'Stringify' used; consider a 'constexpr' template function [cppcoreguidelines-macro-usage]

#define Stringify(s) Stringifyx(s)
        ^

Cpp::Declare("#include<string>");

#define Stringify(s) Stringifyx(s)
#define Stringifyx(...) #__VA_ARGS__
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: variadic macro 'Stringifyx' used; consider using a 'constexpr' variadic template function [cppcoreguidelines-macro-usage]

#define Stringifyx(...) #__VA_ARGS__
        ^

Cpp::TCppScope_t myklass = Cpp::GetNamed("MyKlass");
EXPECT_TRUE(myklass);

size_t num_bases = Cpp::GetNumBases(myklass);
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "size_t" is directly included [misc-include-cleaner]

unittests/CppInterOp/VariableReflectionTest.cpp:6:

+ #include <cstddef>

EXPECT_EQ(datamembers.size(), 5);

EXPECT_EQ(Cpp::GetVariableOffset(datamembers[0], myklass),
((intptr_t)&(my_k.k)) - ((intptr_t)&(my_k)));
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

            ((intptr_t)&(my_k.k)) - ((intptr_t)&(my_k)));
                                     ^

@vgvassilev
Copy link
Contributor

We should probably turn off clang tidy from the unittests.

@Vipul-Cariappa
Copy link
Collaborator Author

Vipul-Cariappa commented Dec 17, 2024

Looks like, if we include a virtual destructor in the base classes these changes are not required.

EDIT
The virtual destructor thing only works for multi-level inheritance. i.e.

class BaseA {};
class BaseB: public BaseA {};

But does not work with multiple inheritance i.e.

class BaseA {};
class BaseB {};
class Klass: public BaseA, public BaseB {};

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 10 out of 17. Check the log or trigger a new build to see more.

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: class 'Base1' defines a non-default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:275: expanded from macro 'CODE'

  class Base1 {                                                                \
        ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: class 'BaseA' defines a non-default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:261: expanded from macro 'CODE'

  class BaseA {                                                                \
        ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: class 'BaseB' defines a non-default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:268: expanded from macro 'CODE'

  class BaseB : public BaseA {                                                 \
        ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: class 'MyKlass' defines a non-default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:283: expanded from macro 'CODE'

  class MyKlass : public BaseB, public Base1 {                                 \
        ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: parameter 'b' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:272: expanded from macro 'CODE'

    BaseB(int x, std::string b) : BaseA(x), b(b) {}                            \
                                              ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: parameter 's' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:280: expanded from macro 'CODE'

    Base1(int i, std::string s) : i(i), s(s) {}                                \
                                          ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: pass by value and use std::move [modernize-pass-by-value]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:272: expanded from macro 'CODE'

    BaseB(int x, std::string b) : BaseA(x), b(b) {}                            \
                 ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: variable 'my_k' is non-const and globally accessible, consider making it const [cppcoreguidelines-avoid-non-const-global-variables]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:289: expanded from macro 'CODE'

  } my_k(5, 4, 3, "Cpp", "Python");
    ^

EXPECT_EQ(datamembers.size(), 5);

EXPECT_EQ(Cpp::GetVariableOffset(datamembers[0], myklass),
((intptr_t)&(my_k.k)) - ((intptr_t)&(my_k)));
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

            ((intptr_t)&(my_k.k)) - ((intptr_t)&(my_k)));
             ^

((intptr_t)&(my_k.k)) - ((intptr_t)&(my_k)));

EXPECT_EQ(Cpp::GetVariableOffset(datamembers[1], myklass),
((intptr_t)&(my_k.a)) - ((intptr_t)&(my_k)));
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

            ((intptr_t)&(my_k.a)) - ((intptr_t)&(my_k)));
                                     ^

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

((intptr_t)&(my_k.k)) - ((intptr_t)&(my_k)));

EXPECT_EQ(Cpp::GetVariableOffset(datamembers[1], myklass),
((intptr_t)&(my_k.a)) - ((intptr_t)&(my_k)));
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

            ((intptr_t)&(my_k.a)) - ((intptr_t)&(my_k)));
             ^

((intptr_t)&(my_k.a)) - ((intptr_t)&(my_k)));

EXPECT_EQ(Cpp::GetVariableOffset(datamembers[2], myklass),
((intptr_t)&(my_k.b)) - ((intptr_t)&(my_k)));
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

            ((intptr_t)&(my_k.b)) - ((intptr_t)&(my_k)));
                                     ^

((intptr_t)&(my_k.a)) - ((intptr_t)&(my_k)));

EXPECT_EQ(Cpp::GetVariableOffset(datamembers[2], myklass),
((intptr_t)&(my_k.b)) - ((intptr_t)&(my_k)));
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

            ((intptr_t)&(my_k.b)) - ((intptr_t)&(my_k)));
             ^

((intptr_t)&(my_k.b)) - ((intptr_t)&(my_k)));

EXPECT_EQ(Cpp::GetVariableOffset(datamembers[3], myklass),
((intptr_t)&(my_k.i)) - ((intptr_t)&(my_k)));
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

            ((intptr_t)&(my_k.i)) - ((intptr_t)&(my_k)));
                                     ^

((intptr_t)&(my_k.b)) - ((intptr_t)&(my_k)));

EXPECT_EQ(Cpp::GetVariableOffset(datamembers[3], myklass),
((intptr_t)&(my_k.i)) - ((intptr_t)&(my_k)));
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

            ((intptr_t)&(my_k.i)) - ((intptr_t)&(my_k)));
             ^

((intptr_t)&(my_k.i)) - ((intptr_t)&(my_k)));

EXPECT_EQ(Cpp::GetVariableOffset(datamembers[4], myklass),
((intptr_t)&(my_k.s)) - ((intptr_t)&(my_k)));
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

            ((intptr_t)&(my_k.s)) - ((intptr_t)&(my_k)));
                                     ^

((intptr_t)&(my_k.i)) - ((intptr_t)&(my_k)));

EXPECT_EQ(Cpp::GetVariableOffset(datamembers[4], myklass),
((intptr_t)&(my_k.s)) - ((intptr_t)&(my_k)));
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

            ((intptr_t)&(my_k.s)) - ((intptr_t)&(my_k)));
             ^

Copy link

codecov bot commented Dec 17, 2024

Codecov Report

Attention: Patch coverage is 97.29730% with 1 line in your changes missing coverage. Please review.

Project coverage is 70.84%. Comparing base (ef2f0a1) to head (0e30059).
Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
lib/Interpreter/CppInterOp.cpp 97.29% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #396      +/-   ##
==========================================
+ Coverage   70.62%   70.84%   +0.21%     
==========================================
  Files           9        9              
  Lines        3500     3529      +29     
==========================================
+ Hits         2472     2500      +28     
- Misses       1028     1029       +1     
Files with missing lines Coverage Δ
include/clang/Interpreter/CppInterOp.h 96.29% <ø> (ø)
lib/Interpreter/CppInterOp.cpp 80.16% <97.29%> (+0.25%) ⬆️
Files with missing lines Coverage Δ
include/clang/Interpreter/CppInterOp.h 96.29% <ø> (ø)
lib/Interpreter/CppInterOp.cpp 80.16% <97.29%> (+0.25%) ⬆️

Copy link
Contributor

@vgvassilev vgvassilev left a comment

Choose a reason for hiding this comment

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

LGTM, just make clang-tidy happy about this missing include.

@mcbarton
Copy link
Collaborator

mcbarton commented Dec 17, 2024

We should probably turn off clang tidy from the unittests.

@vgvassilev @Vipul-Cariappa If you want clang tidy to not provide comments on unit tests then you'll want to change

- '**.h'
- '**.cpp'
to only look in the lib and include folders.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

@@ -7,6 +7,8 @@

#include "gtest/gtest.h"
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: 'gtest/gtest.h' file not found [clang-diagnostic-error]

#include "gtest/gtest.h"
         ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: class 'Base1' defines a non-default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:277: expanded from macro 'CODE'

  class Base1 {                                                                \
        ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: class 'BaseA' defines a non-default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:263: expanded from macro 'CODE'

  class BaseA {                                                                \
        ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: class 'BaseB' defines a non-default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:270: expanded from macro 'CODE'

  class BaseB : public BaseA {                                                 \
        ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: class 'MyKlass' defines a non-default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:285: expanded from macro 'CODE'

  class MyKlass : public BaseB, public Base1 {                                 \
        ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: parameter 'b' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:274: expanded from macro 'CODE'

    BaseB(int x, std::string b) : BaseA(x), b(b) {}                            \
                                              ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: parameter 's' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:282: expanded from macro 'CODE'

    Base1(int i, std::string s) : i(i), s(s) {}                                \
                                          ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: pass by value and use std::move [modernize-pass-by-value]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:274: expanded from macro 'CODE'

    BaseB(int x, std::string b) : BaseA(x), b(b) {}                            \
                 ^

: BaseB(x, b), Base1(i, s), k(k) {} \
} my_k(5, 4, 3, "Cpp", "Python");

CODE
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: variable 'my_k' is non-const and globally accessible, consider making it const [cppcoreguidelines-avoid-non-const-global-variables]

CODE
^
Additional context

unittests/CppInterOp/VariableReflectionTest.cpp:291: expanded from macro 'CODE'

  } my_k(5, 4, 3, "Cpp", "Python");
    ^

@Vipul-Cariappa Vipul-Cariappa merged commit 5d81a80 into compiler-research:main Dec 18, 2024
47 checks passed
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.

3 participants