Main Content

Fix Polyspace Linking Errors About Conflicting Declarations in Different Translation Units

Issue

The analysis shows an error or warning similar to one of these error messages:

  • Declaration of [...] is incompatible with a 
    declaration in another translation unit ([...])

    This message appears when the conflicting declarations do not come from the same header file.

  • When one of the conflicting declarations is in a header file.

    Declaration of [...] had a different meaning during compilation of [...] ([...])

    This message appears when the conflicting declarations come from the same header file included in different source files.

The error indicates that the same variable or function or data type is declared differently in different translation units. The conflicting declarations violate the One Definition Rule (cf. C++Standard, ISO/IEC 14882:2003, Section 3.2). When conflicting declarations occur, Polyspace® Code Prover™ does not choose a declaration and continue analysis.

Common compilation toolchains often do not store data type information during the linking process. The conflicting declarations do not cause errors with your compiler. Polyspace Code Prover follows stricter standards for linking to guarantee the absence of certain run-time errors.

To identify the root cause of the error:

  1. From the error message, identify the two source files with the conflicting declarations.

    For instance, an error message looks like this message:

    C:\field.h, line 1: declaration of class "a_struct" had
          a  different meaning during compilation of "file1.cpp"
    | struct a_struct {
    |
    | Detected during compilation of secondary translation unit "file2.cpp"
    The message shows that the structure a_struct has a conflicting declaration in file1.cpp and file2.cpp, both of which include the header file field.h.

    An alternative error message can look like this:

    C:\field2.h, line 1: declaration of class "a_struct" had
          is incompatible with a declaration in another translation unit
    | the other declaration is at line 1 of field1.h"
    | struct a_struct {
    |
    | Detected during compilation of secondary translation unit "file2.cpp"
    The message shows that the structure a_struct has a conflicting declaration in field2.h and field.h. The header file field2.h is included in the source file file2.cpp.

  2. Try to identify the conflicting declarations in the source files.

    Otherwise, open the translation units containing these files. Sometimes, the translation units or preprocessed files show the conflicting declarations more clearly than the source files because the preprocessor directives, such as #include and #define statements, are replaced appropriately and the macros are expanded.

    1. Rerun the analysis with the flag -keep-relaunch-files so that all translation units are saved. In the user interface, enter the flag for the option Other.

      The analysis stops after compilation. The translation units or preprocessed files are stored in a zipped file ci.zip in a subfolder .relaunch of the results folder.

    2. Unzip the contents of ci.zip.

      The preprocessed files have the same name as the source files. For instance, the preprocessed file with file1.cpp is named file1.ci.

    When you open the preprocessed files at the line numbers stated in the error message, you can spot the conflicting declarations.

Possible Cause: Variable Declaration and Definition Mismatch

A variable declaration does not match its definition. For instance:

  • The declaration and definition use different data types.

  • The variable is declared as signed, but defined as unsigned.

  • The declaration and definition uses different type qualifiers.

  • The variable is declared as an array, but defined as a non-array variable.

  • For an array variable, the declaration and definition use different array sizes.

In this example, the code shows a linking error because of a mismatch in type qualifiers. The declaration in file1.c does not use type qualifiers, but the definition in file2.c uses the volatile qualifier.

file1.cfile2.c
extern int x;           

void main(void)
{/* Variable x used */}
 volatile int x;

In these cases, you can typically spot the difference by looking at the source files. You do not need to see the preprocessed files.

Solution

Make sure that the variable declaration matches its definition.

Possible Cause: Function Declaration and Definition Mismatch

A function declaration does not match its definition. For instance:

  • The declaration and definition use different data types for arguments or return values.

  • The declaration and definition use a different number of arguments.

  • A variable-argument or varargs function is declared in one function, but it is called in another function without a previous declaration.

    In this case, the error message states that the required prototype for the function is missing.

In this example, the code shows a linking error because of a mismatch in the return type. The declaration in file1.c has return type int, but the definition in file2.c has return type float.

file1.cfile2.c
int input(void);

void main() {
  int val = input();
}
float input(void) {
  float x = 1.0;
  return x;
}

In these cases, you can typically find the difference by looking at the source files. You do not need to see the preprocessed files.

Solution

Make sure that the function declaration matches its definition.

Even if your build process allows these errors, you can have unexpected results during run time. If a function declaration and definition with conflicting prototypes exist in your code, when you call the function, the result can be unexpected.

For a variable-argument or varargs function, declare the function before you call it. If you do not want to change your source code, you can work around this linking error.

  1. Add the function declaration in a separate file.

  2. Only for the purposes of verification, #include this file in every source file by using the option Include (-include).

Possible Cause: Conflicts from Unrelated Declarations

You use the same identifier name for two unrelated objects. These are some common reasons for unrelated objects in the same Polyspace project:

  • You intended to declare the objects static so that they do not have external linkage, but omitted the static specifier.

  • You declared the same object in several source files instead of putting the declaration in a header file and including in the source files.

  • You created a Polyspace project from a build command using the polyspace-configure command. The build command created several independent binaries, but files involved in all the binaries were collected in one Polyspace project.

Solution

Depending on the root cause for unrelated objects using the same name, use an appropriate solution.

If your Polyspace project was created from a build command and source files for independent binaries were clubbed together, split the project into modules when tracing your build command. See:

Possible Cause: Macro-dependent Definitions

A variable definition is dependent on a macro being defined earlier. One source file defines the macro while another does not, causing conflicts in variable definitions.

In this example, file1.cpp and file2.cpp include a header file field.h. The header file defines a structure a_struct that is dependent on a macro definition. Only one of the two files, file2.cpp, defines the macro DEBUG. The definition of a_struct in the translation unit with file1.cpp differs from the definition in the unit with file2.cpp.

file1.cppfile2.cpp
#include "field.h"

int main()
{
    a_struct s;
    init_a_struct(&s);
    return 0;
}
#define DEBUG

#include <string.h>
#include "field.h"

void init_a_struct(a_struct* s)
{
    memset(s, 0, sizeof(*s));
}

field.h:

struct a_struct {
    int n;
#ifdef DEBUG
    int debug;
#endif
};

When you open the preprocessed files file1.ci and file2.ci, you see the conflicting declarations.

file1.cifile2.ci
struct a_struct {
    int n;



};
struct a_struct {
    int n;

    int debug;

};

Solution

Avoid macro-dependent definitions. Otherwise, fix the linking errors. Make sure that the macro is either defined or undefined on all paths that contain the variable definition.

Possible Cause: Keyword Redefined as Macro

A keyword is redefined as a macro, but not in all files.

In this example, bool is a keyword in file1.cpp, but it is redefined as a macro in file2.cpp.

file1.cppfile2.cpp
#include "bool.h"

int main()
{
    return 0;
}
#define false 0
#define true (!false)

#include "bool.h"

bool.h:

template <class T>
struct a_struct {
    bool flag;
    T t;
    a_struct() {
        flag = true;
    }
};

Solution

Be consistent with your keyword usage throughout the program. Use the keyword defined in a standard library header or use your redefined version.

Possible Cause: Differences in Structure Packing

A #pragma pack(n) statement changes the structure packing alignment, but not in all files. See also Code Prover Assumptions About #pragma Directives.

In this example, the default packing alignment is used in file1.cpp, but a #pragma pack(1) statement enforces a packing alignment of 1 byte in file2.cpp.

file1.cppfile2.cpp
int main()
{
    return 0;
}
#pragma pack(1)

#include "pack.h"

pack.h:

struct a_struct {
    char ch;
    short sh;
};

Solution

Enter the #pragma pack(n) statement in the header file so that it applies to all source files that include the header.