c++keilarmcc

Copy constructor for C volatile bitfield struct


Good day

I am trying to use a C SD driver/file system libary (Keil MDK), in a C++11 project. It was added by the Pack manager in Keil MDK 5.23. I am compiling with ARMCC 5.06u4

I get the warning class "_ARM_MCI_STATUS" has no suitable copy constructor" which is odd, because the header it is declared in has extern "C" {.

By default, the pack has no option to set it to C or C++, but I have manually added the file as a C file. Still a problem.

The struct is declared, within extern "C" { as:

typedef volatile struct _ARM_MCI_STATUS {
    uint32_t command_active   : 1;        ///< Command active flag
    uint32_t command_timeout  : 1;        ///< Command timeout flag (cleared on start of next command)
    uint32_t command_error    : 1;        ///< Command error flag (cleared on start of next command)
    uint32_t transfer_active  : 1;        ///< Transfer active flag
    uint32_t transfer_timeout : 1;        ///< Transfer timeout flag (cleared on start of next command)
    uint32_t transfer_error   : 1;        ///< Transfer error flag (cleared on start of next command)
    uint32_t sdio_interrupt   : 1;        ///< SD I/O Interrupt flag (cleared on start of monitoring)
    uint32_t ccs              : 1;        ///< CCS flag (cleared on start of next command)
    uint32_t reserved         : 24;
} ARM_MCI_STATUS;

The problem occurs when the struct is being returned at:

static ARM_MCI_STATUS GetStatus (MCI_RESOURCES *mci) {
  return mci->info->status;
}

Where status is declared as ARM_MCI_STATUS status;. I don't see why it should be an issue.

If I compile without the --cpp then it compiles without issue.

Any suggestions?


Solution

  • Just because your struct is marked extern "C" doesn't mean it won't still be compiled as C++ code.

    This means that return mci->info->status; invokes the implicitly generated copy constructor. Because _ARM_MCI_STATUS is marked volatile, it's members are, which means the default copy constructor which takes T& can't bind to the volatile lvalue reference it's passed.

    This is explained in the cppreference explanation:

    Otherwise, the implicitly-declared copy constructor is T::T(T&). (Note that due to these rules, the implicitly-declared copy constructor cannot bind to a volatile lvalue argument.)

    And also in the actual standard (Just having a hard time finding the correct clause but it's in there).