[cfe-dev] PATCH: C++ overload resolution

Doug Gregor doug.gregor at gmail.com
Tue Sep 9 00:00:16 PDT 2008


This patch implements part of C++ overload resolution for calls to
overloaded functions, e.g.,

  void f(int); // #1
  void f(double); // #2
  void f(); // #3

  f((short)1); // calls #1
  f(1.0f); // calls #2

The patch itself (clang-overloading.patch) is rather large. It should
be applied on top of my overloaded function declarations patch
(updated version attached as clang-overloaded-function-decls.patch).
If you want "make test" to run cleanly, please also apply the little
patch I just sent separately that makes "expected-note {{ ... }}" work
in test cases.

What's implemented:
  - Computation of the implicit conversion sequence required to
initialize a function parameter from its corresponding argument. Many
of the standard conversions (C++ clause 4) are implemented, including
most integral and floating point conversions, boolean conversions,
some pointer conversions, etc. The ellipsis conversion sequence is
also implemented.
  - Comparison and ranking of implicit conversion sequences (is this
ICS better or worse than that one?)
  - Comparison of two candidates in the overload set based on their
ICSs; determination of the best viable function
  - Diagnostics for failures due to overload resolution ambiguity, no
viable function
  - Overload resolution for a call to an overloaded function

What's not implemented:
  - Reference binding (reference support needs a lot of work, first)
  - Overloading for calls to member functions (it's missing the
"implicit object parameter" functionality)
  - Several of the implicit conversion sequence and standard
conversion sequence ranking rules
  - User-defined conversions
  - Derived-to-base pointer conversions
  - Integral bit-field promotions
  - Pointer-to-member conversions
  - Everything else marked FIXME in SemaOverload.cpp
  - I didn't get around to making DeclRefExpr use a NamedDecl, as
Argiris suggested. I'll do this later.

Please see the test case overload-call.cpp for the kinds of examples
that do work. If you try something that doesn't work and doesn't
relate to a FIXME in the code, please tell me! Overloading is
complicated enough that there is really no such thing as a
comprehensive test suite, and little errors in this code can cause
bigger problems down the road. The more examples, the better.

The design of this overload resolution mechanism is relatively
straightforward. The most complex part of the code is in computing the
implicit conversion sequence for a parameter type/argument pair, which
essentially has to know about all of the kinds of implicit conversions
in C++. The not-so-wonderfully-named Sema::CopyInitializeParameter
function is the entry point to this computation: it attempts to find
an implicit conversion sequence to initialize a parameter from an
argument, without producing any diagnostics or generating any new
expressions. The implicit conversion sequences are stored with each
candidate function in the overload set, and are used later to
determine the best viable function.

Overload resolution is triggered by Sema::ActOnCallExpr. If it
receives an OverloadedFunctionDecl, it first attempts overload
resolution. If that was successful, we just build a new function
argument that refers to the best viable function and continue as if
the OverloadedFunctionDecl never exists. For the other 6 contexts in
which overload resolution might occur, we would follow the same
pattern.

There is some duplication in the effort that we do to find the
implicit conversion sequence (Sema::CopyInitializeParameter) and to
actually build the AST nodes to perform the conversion
(Sema::CheckSingleAssignmentConstraints). In the long term, I expect
there will be more code sharing. However, I did not attempt this now
for several reasons:

  - CheckSingleAssignmentConstraints will eventually have to be
replaced with a new routine PerformCopyInitialization that
copy-initializes the parameter from the argument, and deals with all
of the associated C++ semantics. For now,
CheckSingleAssignmentConstraints is a "good enough" approximation to
deal with function calls, at least until we have support for copy
constructors and so on.

  - The usage modes for these functions are very different:
CopyInitializeParameter looks at the conversions and records what
would happen, but never performs conversions or complains if something
fails. CheckSingleAssignmentConstraints, on the other hand, performs
the conversion, building new AST nodes and complaining about any
errors it finds. Note that CopyInitializeParameter does a lot less
work, and (so far) does not need to allocate any memory. So it's
faster than CheckSingleAssignmentConstraints and should stay that way.

  - A complete merge of these two routines is unlikely, and possibly
undesirable. It's more likely that we'll factor out common
how-does-this-conversion-happen checks.

  - For performance reasons, I eventually hope that we can use the
results of computing the implicit conversion sequence to accelerate
the task of actually performing the conversions. For example, if
CopyInitializeParameter performs overload resolution to find a
user-defined conversion operator, CheckSingleAssignmentConstraints (or
whatever it evolves into) could use the result of that overload
resolution without going through the work of doing it a second time.

As part of implementing overload resolution, I found several places
where I had to improve C++ support in Clang to be able to test the
overload resolution mechanism. These could (should) be split into
separate patches, but I don't have time to do so at the moment. These
changes are:
  - "bool" is not an extension in C++. See AddKeyword in
lib/Basic/IdentifierTable.cpp.

  - The type of a string literal in C++ is an array of const char (or
array of const wchar_t). See Sema::ActOnStringLiteral.

  - There is a (deprecated) conversion from a string literal to a
char* or wchar_t* in C++. My solution to this is pretty ugly, because
I went for something minimally invasive; see
Sema::DiagnoseAssignmentResult and
Sema::IsStringLiteralToNonConstPointerConversion.

Comments greatly appreciated!

  - Doug
-------------- next part --------------
A non-text attachment was scrubbed...
Name: clang-overloaded-function-decls.patch
Type: application/octet-stream
Size: 30272 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20080909/0da24ed6/attachment.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: clang-overloading.patch
Type: application/octet-stream
Size: 56323 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20080909/0da24ed6/attachment-0001.obj>


More information about the cfe-dev mailing list