fodinabor
fodinabor

Reputation: 426

How to make clang build (like msvc and gcc) with double declared extern "C" functions in different namespaces

I have this project, where two other projects get included, that provide headers for the same DLL. In one header the declarations are put into a namespace, in the other one not. That works well for GCC and MSVC, but I can't convince clang to compile it.. So a minimal example would be:

x.h:

#include <string>
#if defined __GNUC__
# pragma GCC system_header
#endif // __GNUC__

namespace XX {
  struct Type {
    std::string name;
  };

  extern "C" int Func(Type);
}

incl.h:

#include <string>
#if defined __GNUC__
# pragma GCC system_header
#endif // __GNUC__

struct Type {
  std::string name;
};

extern "C" int Func(Type);

main.cpp

#include "incl.h"
#include "x.h"

int main()
{
  return 0;
}

G++ complains with a warning, but that is turned off with # pragma GCC system_header. So, how can I get clang to build in an environment like this?

Upvotes: 2

Views: 152

Answers (1)

eerorika
eerorika

Reputation: 238441

[dcl.link] At most one function with a particular name can have C language linkage. Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function. ...

As such, ::Func and XX::Func must refer to the same function. But your two declarations have different parameter lists - one takes a parameter of ::Type while the other takes a parameter of XX::Type. As such, they cannot be the same function, and thus the quoted rule is violated, and the program is ill-formed.ever

A few ways to fix the program:

  • Rename either XX::Func or ::Func so that they are separate functions. Make sure that there is a definition for each.
  • In incl.h, include x.h and replace the definition of ::Type with using XX::Type. So that each Type refers to the same type, and consequently both function names refer to the same function. Make sure that there is only one definition.
  • In x.h, include incl.h and replace the definition of XX::Type with using ::Type. To achieve the same as above.

The latter is by the way how some standard library implementations implement <cstdlib> and its friends. They include the corresponding C standard library header (<stdlib.h> in the case of <cstdlib>) which declares everything in global namespace (the only "namespace" in C), and then they pick all of the standard functions and types into std namespace with using ::whatever.


P.S. Don't use #pragma GCC system_header (unless you're writing a system header). It will suppress all warnings (except those produced by #warning directive).

Upvotes: 3

Related Questions