Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot declare an operator within a function. Clang bug or spec?

One of the weirder corner cases of C is that functions can be declared within other functions, e.g.

void foo(void)
{
  void bar(void); // Behaves as if this was written above void foo(void)
  bar();
}

This has carried through into C++, at least for most functions. Clang doesn't appear to recognise the pattern if the function in question happens to be called operator==.

struct foo
{
  int value;
};

struct bar
{
  foo value;
};

bool wot(const bar &x, const bar &y)
{
  bool eq(const foo &, const foo &);         // Declare function eq
  bool operator==(const foo &, const foo &); // Declare function operator==
  bool func = eq(x.value, y.value);          // This line compiles fine
  bool call = operator==(x.value, y.value);  // Also OK - thanks user657267!
  bool op = x.value == y.value;              // This one doesn't
  return func && call && op;
}

bool test()
{
  bar a;
  bar b;
  return wot(a,b);
}

GCC and ICC compile this fine. Checking name mangling in the object suggests the operator== has been declared with the right types. Clang (I tried up to 3.8) errors:

error: invalid operands to binary expression
      ('const foo' and 'const foo')
      bool op = x.value == y.value;
                ~~~~~~~ ^  ~~~~~~~

Unless the declaration is moved to directly above the function, in which case Clang is happy too:

bool operator==(const foo &, const foo &);
bool wot(const bar &x, const bar &y)
{
  return x.value == y.value; // fine
}

I can't use this workaround as the "real world" case that provoked this question involves layers of templates, meaning I only know the type name "foo" within the function declaration.

I believe this is a bug in Clang - is there special handling of operatorX free functions which prohibits declaring them within a function?

like image 902
Jon Chesterfield Avatar asked Mar 22 '16 09:03

Jon Chesterfield


1 Answers

For overloaded operators, see [over.match.oper]/(3.2):

[…] for a binary operator @ with a left operand of a type whose cv-unqualified version is T1 and a right operand of a type whose cv-unqualified version is T2, […] non-member candidates […] are constructed as follows:

The set of non-member candidates is the result of the unqualified lookup of operator@ in the context of the expression according to the usual rules for name lookup in unqualified function calls (3.4.2) except that all member functions are ignored. However, if no operand has a class type, […]

That is, we have the exact same name lookup rules as in ordinary calls, because x.value is of class type (foo). It's a Clang bug, and it occurs with all binary operators. Filed as #27027.

like image 95
Columbo Avatar answered Oct 07 '22 06:10

Columbo