Skip to content

Fix compile error caused by customized mapping of enums during JSONSerialization #78009

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

Conversation

2horse9sun
Copy link

Changes

In JSONSerialization.h, if I map an enum into json by implementing ScalarBitSetTraits::bitset() method, the result of the logical operation of two enums (which is int) will be assigned to an enum, which causes the compile error.

The changes are:

  • Use static_cast<T> to convert the result in all bitset related methods.

Rationale

I'm trying to extract the Swift and Objective-C AST into separate JSON files. During the extraction, I take advantage of swift's JSONSerialization tools to perform the mapping from AST nodes to json objects. However, some compile errors occur during the process. The following demo is a simplified version of what I'm doing:

// Map Decl::ObjCDeclQualifier into json
template <>
struct ScalarBitSetTraits<Decl::ObjCDeclQualifier> {
    static void bitset(Output &out, Decl::ObjCDeclQualifier &kind) {
        out.bitSetCase(kind, "none",   Decl::ObjCDeclQualifier::OBJC_TQ_None);
        out.bitSetCase(kind, "in",   Decl::ObjCDeclQualifier::OBJC_TQ_In);
        out.bitSetCase(kind, "inout",   Decl::ObjCDeclQualifier::OBJC_TQ_Inout);
        out.bitSetCase(kind, "bycopy",   Decl::ObjCDeclQualifier::OBJC_TQ_Bycopy);
        out.bitSetCase(kind, "byref",   Decl::ObjCDeclQualifier::OBJC_TQ_Byref);
        out.bitSetCase(kind, "oneway",   Decl::ObjCDeclQualifier::OBJC_TQ_Oneway);
        out.bitSetCase(kind, "cs_nullability",   Decl::ObjCDeclQualifier::OBJC_TQ_CSNullability);
    }
};

int main(int argc, const char *argv[]) {
    std::error_code stream_error;
    llvm::raw_fd_ostream outputStream(StringRef("-"), stream_error);
    Output serializer(outputStream, {}, false);
    serializer.beginObject();
    Decl::ObjCDeclQualifier value = Decl::ObjCDeclQualifier::OBJC_TQ_None;
    serializer.mapRequired("key", value);
    serializer.endObject();
    return 0;
}

The above demo is built as a swift tool (the detail is omitted). When I run the demo, the compiler complains that:

error: assigning to 'clang::Decl::ObjCDeclQualifier' from incompatible type 'int'
      Val = Val | ConstVal;

It turns out that Decl::ObjCDeclQualifier is enum but the result of Val | ConstVal is int. That seems to be the root cause of the error. Then I modify the source code of JSONSerialization.h by statically cast the result:

  template <typename T>
  void bitSetCase(T &Val, const char* Str, const T ConstVal) {
    if (bitSetMatch(Str, (Val & ConstVal) == ConstVal)) {
      Val = static_cast<T>(Val | ConstVal);
      // Val = Val | ConstVal;
    }
  }

After that, it works and the json serialization results are correct.

@2horse9sun
Copy link
Author

@swift-ci Please test

@DougGregor
Copy link
Member

@swift-ci please smoke test

@DougGregor DougGregor merged commit bfae734 into swiftlang:main Dec 11, 2024
3 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.

2 participants