Skip to content

Update GetBinaryOperator to GetOperator #394

New issue

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

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

Already on GitHub? # to your account

Merged
merged 2 commits into from
Jan 4, 2025

Conversation

Vipul-Cariappa
Copy link
Collaborator

Description

Resolving unary operators and operators defined within namespaces.
Required for + op in std::string.

Fixes (issue)

Three issues at cppyy. Requires a patch for both CPyCppyy and cppyy-backend.

Type of change

Please tick all options which are relevant.

  • Bug fix
  • New feature
  • Requires documentation updates

Testing

I have added in tests cases for unary operator lookup and lookup of operator within a namespace.

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

Copy link

codecov bot commented Dec 16, 2024

Codecov Report

Attention: Patch coverage is 81.25000% with 3 lines in your changes missing coverage. Please review.

Project coverage is 70.85%. Comparing base (8c0cd6d) to head (6cf8923).
Report is 3 commits behind head on main.

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

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #394      +/-   ##
==========================================
- Coverage   70.87%   70.85%   -0.02%     
==========================================
  Files           9        9              
  Lines        3533     3538       +5     
==========================================
+ Hits         2504     2507       +3     
- Misses       1029     1031       +2     
Files with missing lines Coverage Δ
include/clang/Interpreter/CppInterOp.h 96.29% <ø> (ø)
lib/Interpreter/CppInterOp.cpp 80.14% <81.25%> (-0.06%) ⬇️
Files with missing lines Coverage Δ
include/clang/Interpreter/CppInterOp.h 96.29% <ø> (ø)
lib/Interpreter/CppInterOp.cpp 80.14% <81.25%> (-0.06%) ⬇️

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.

Maybe address the clang-tidy issue.

@Vipul-Cariappa Vipul-Cariappa force-pushed the dev/operators branch 2 times, most recently from 371ef22 to 709371e Compare December 18, 2024 07:13
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

OP_Coawait,
};

enum OperatorKind {
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: enum 'OperatorKind' uses a larger base type ('unsigned int', size: 4 bytes) than necessary for its value set, consider using 'std::uint8_t' (1 byte) as the base type to reduce its size [performance-enum-size]

  enum OperatorKind {
       ^

if (auto* FD = llvm::dyn_cast<FunctionDecl>(D)) {
if (FD->isOverloadedOperator()) {
switch (FD->getOverloadedOperator()) {
#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, \
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 'OVERLOADED_OPERATOR' used; consider a 'constexpr' template function [cppcoreguidelines-macro-usage]

#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary,            \
        ^

Copy link
Contributor

Choose a reason for hiding this comment

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

That type of check should be disabled in our clang-tidy config..

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

Comment on lines 90 to 92
kUnary = 0b001,
kBinary = 0b010,
kBoth = 0b011,
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess we won't or these, 1,2,3 should be fine...

OP_Coawait,
};

enum OperatorKind {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
enum OperatorKind {
enum OperatorArity {

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

};

enum OperatorArity { kUnary = 1, kBinary, kBoth };
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: enum 'OperatorArity' uses a larger base type ('unsigned int', size: 4 bytes) than necessary for its value set, consider using 'std::uint8_t' (1 byte) as the base type to reduce its size [performance-enum-size]

  enum OperatorArity { kUnary = 1, kBinary, kBoth };
       ^

@@ -3262,22 +3262,56 @@ namespace Cpp {
return PI->getNameAsString();
}

void GetBinaryOperator(TCppScope_t scope, enum BinaryOperator op,
std::vector<TCppFunction_t>& operators) {
bool IsUnaryOperator(TCppScope_t scope) {
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: redundant explicit casting to the same type 'Expr *' as the sub-expression, remove this casting [readability-redundant-casting]

Suggested change
bool IsUnaryOperator(TCppScope_t scope) {
Expr *DefaultArgExpr = PI->getDefaultArg();
Additional context

llvm/include/clang/AST/Decl.h:1809: source type originates from the invocation of this method

  Expr *getDefaultArg();
        ^

switch (FD->getOverloadedOperator()) {
#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, \
MemberOnly) \
case OO_##Name: \
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]

    auto *D = (clang::Decl *)method;
              ^

}
}
return false;
}
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]

    auto *D = (clang::Decl *)func;
              ^

if (auto* DC = llvm::dyn_cast_or_null<DeclContext>(D)) {
ASTContext& C = getSema().getASTContext();
DeclContextLookupResult Result =
DC->lookup(C.DeclarationNames.getCXXOperatorName(
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: Called C++ object pointer is null [clang-analyzer-core.CallAndMessage]

    return PI->getNameAsString();
           ^
Additional context

lib/Interpreter/CppInterOp.cpp:3299: 'PI' initialized to a null pointer value

    clang::ParmVarDecl* PI = nullptr;
    ^

lib/Interpreter/CppInterOp.cpp:3301: Assuming null pointer is passed into cast

    if (auto* FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(D))
                   ^

lib/Interpreter/CppInterOp.cpp:3301: 'FD' is null

    if (auto* FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(D))
              ^

lib/Interpreter/CppInterOp.cpp:3301: Taking false branch

    if (auto* FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(D))
    ^

lib/Interpreter/CppInterOp.cpp:3303: Assuming null pointer is passed into cast

    else if (auto* FD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
                        ^

lib/Interpreter/CppInterOp.cpp:3303: 'FD' is null

    else if (auto* FD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
                   ^

lib/Interpreter/CppInterOp.cpp:3303: Taking false branch

    else if (auto* FD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
         ^

lib/Interpreter/CppInterOp.cpp:3306: Called C++ object pointer is null

    return PI->getNameAsString();
           ^

};

enum OperatorArity { kUnary = 1, kBinary, kBoth };
Copy link
Contributor

@vgvassilev vgvassilev Dec 18, 2024

Choose a reason for hiding this comment

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

Suggested change
enum OperatorArity { kUnary = 1, kBinary, kBoth };
enum OperatorArity { kBoth = 0, kUnary, kBinary };

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I did not understand this.
All Unary operators are not Binary operators. So kBoth = 0 and kUnary = 0 is confusing. Example ~ operator.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, my bad, fixed the suggestion.

void GetBinaryOperator(TCppScope_t scope, enum BinaryOperator op,
std::vector<TCppFunction_t>& operators);
///\returns true if scope is a unary operator
bool IsUnaryOperator(TCppScope_t scope);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
bool IsUnaryOperator(TCppScope_t scope);
bool IsUnaryOperator(TCppFunction_t op);

bool IsUnaryOperator(TCppScope_t scope);

///\returns true if scope is a binary operator
bool IsBinaryOperator(TCppScope_t scope);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
bool IsBinaryOperator(TCppScope_t scope);
bool IsBinaryOperator(TCppFunction_t op);

if (auto* FD = llvm::dyn_cast<FunctionDecl>(D)) {
if (FD->isOverloadedOperator()) {
switch (FD->getOverloadedOperator()) {
#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, \
Copy link
Contributor

Choose a reason for hiding this comment

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

That type of check should be disabled in our clang-tidy config..

Comment on lines 3312 to 3338
if (auto* FD = llvm::dyn_cast<FunctionDecl>(D)) {
if (FD->isOverloadedOperator()) {
switch (FD->getOverloadedOperator()) {
#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, \
MemberOnly) \
case OO_##Name: \
return Unary;
#include "clang/Basic/OperatorKinds.def"
default:
break;
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

We should move that into a utility function, write the switch such that it returns

OperatorArity getOperatorArity(...) {
  if (Unary && Binary) return kBoth; ...
}

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

};

enum OperatorArity { kNone, kUnary, kBinary, kBoth };
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: enum 'OperatorArity' uses a larger base type ('unsigned int', size: 4 bytes) than necessary for its value set, consider using 'std::uint8_t' (1 byte) as the base type to reduce its size [performance-enum-size]

  enum OperatorArity { kNone, kUnary, kBinary, kBoth };
       ^

}
}
}
return kNone;
Copy link
Contributor

Choose a reason for hiding this comment

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

That should be unreachable, right? What does it mean arity::kNone? An operator without arguments? I do not think that's possible.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, should be unreachable.
It is for cases when the argument is something other than an operator or a function that is not an operator.

Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't that be an assert or an early exit?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I will say this is simpler. Assert will crash the program. In this case, the user can handle kNone as an error.

Also if I remove the return, clang-tidy will get angry.

Let me know if you still think we should remove kNone. I can do that, but not sure how I would satisfy clang-tidy's message of Non-void function does not return a value in all control paths.

Copy link
Contributor

Choose a reason for hiding this comment

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

You should remove it. You can return ~0U

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Compiler error:

/home/vipul-cariappa/Workspace/cpp-py/compiler-research/CppInterOp/lib/Interpreter/CppInterOp.cpp:3339:12: error: invalid conversion from ‘unsigned int’ to ‘Cpp::OperatorArity’ [-fpermissive]
 3339 |     return ~0U;
      |            ^~~
      |            |
      |            unsigned int

Should I rename it to kInvalid instead?

Copy link
Contributor

Choose a reason for hiding this comment

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

Cast it to OperatorArity?

if (auto* FD = llvm::dyn_cast<Decl>(D))
operators.push_back(FD);
for (auto* i : Result) {
if (kind & getOperatorArity(i))
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if (kind & getOperatorArity(i))
if (kind == getOperatorArity(i))

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

When kind = kBoth should we return Unary $\cap$ Binary or Unary $\cup$ Binary?
This logic using & returns Unary $\cup$ Binary.
Whereas == will return Unary $\cap$ Binary.

Operators like - is both Unary and Binary.

I set the enum OperatorArity values so that I can perform this bitwise operation.

Copy link
Contributor

Choose a reason for hiding this comment

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

When I say kBoth, I expect all unary and binary operators to be present in that list.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In that case, we should be using &. kUnary = 0b001 and kBinary = 0b010 and kBoth = kUnary ^ kBinary = 0b011.
No changes are required here.

@vgvassilev
Copy link
Contributor

Do we know why the check if failing?

@aaronj0
Copy link
Collaborator

aaronj0 commented Dec 20, 2024

Do we know why the check if failing?

Looks like the API update in cppyy-backend was not pulled, rerunning now. should be green

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

}
}
}
return (OperatorArity)~0U;
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: The value '4294967295' provided to the cast expression is not in the valid range of values for 'OperatorArity' [clang-analyzer-optin.core.EnumCastOutOfRange]

    return (OperatorArity)~0U;
           ^
Additional context

include/clang/Interpreter/CppInterOp.h:88: enum declared here

  enum OperatorArity { kUnary = 1, kBinary, kBoth };
       ^

lib/Interpreter/CppInterOp.cpp:3319: Assuming 'D' is not a 'CastReturnType'

    if (auto* FD = llvm::dyn_cast<FunctionDecl>(D)) {
                   ^

lib/Interpreter/CppInterOp.cpp:3319: 'FD' is null

    if (auto* FD = llvm::dyn_cast<FunctionDecl>(D)) {
              ^

lib/Interpreter/CppInterOp.cpp:3319: Taking false branch

    if (auto* FD = llvm::dyn_cast<FunctionDecl>(D)) {
    ^

lib/Interpreter/CppInterOp.cpp:3338: The value '4294967295' provided to the cast expression is not in the valid range of values for 'OperatorArity'

    return (OperatorArity)~0U;
           ^

resolving unary operators and operators defined within namespaces
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!

@Vipul-Cariappa Vipul-Cariappa merged commit c446c3e into compiler-research:main Jan 4, 2025
47 checks passed
@Vipul-Cariappa Vipul-Cariappa deleted the dev/operators branch January 4, 2025 03:07
Vipul-Cariappa added a commit to Vipul-Cariappa/cppyy-compiler-research that referenced this pull request Jan 6, 2025
Vipul-Cariappa added a commit to compiler-research/cppyy that referenced this pull request Jan 6, 2025
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants