[cfe-commits] r65385 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDecl.cpp test/Sema/var-redecl.c test/Sema/vla.c

Douglas Gregor dgregor at apple.com
Wed Feb 25 10:10:09 PST 2009


On Feb 24, 2009, at 4:30 PM, Eli Friedman wrote:

> On Tue, Feb 24, 2009 at 1:24 PM, Douglas Gregor <dgregor at apple.com>  
> wrote:
>>
>> On Feb 24, 2009, at 1:02 PM, Eli Friedman wrote:
>>
>>> On Tue, Feb 24, 2009 at 11:23 AM, Douglas Gregor <dgregor at apple.com>
>>> wrote:
>>>>
>>>> +  // FIXME: We don't do this in C++ because, although we would  
>>>> like
>>>> +  // to get the extra checking that this operation implies,
>>>> +  // the declaration itself is not visible according to C++'s  
>>>> rules.
>>>
>>> It isn't visible according to C's rules either... what exactly is  
>>> the
>>> issue here?
>>
>>
>> The issue is that we want to diagnose cases where there are  
>> incompatible
>> declarations even when those declarations aren't necessarily visible.
>
> I follow that, but is C++ different in this regard?


Technically, no. There are other issues that make this both hard to do  
and less important in C++.

It's less important because functions aren't implicitly declared in C+ 
+, so we won't run into the case where a function shows up in a local  
scope

	void f() {
		int otherfunc(int, int);
	}

and then gets some (conflicting) implicit declaration later in the file:

	void g() {
		outerfunc(5);
	}

The call inside g() is an error in C++, so the user will see the  
problem anyway. Granted, we won't diagnose problems like this in C++:

	void f2() {
		int otherfunc(int); // conflicts with the declaration of otherfunc  
in f
	}

C++ has other features that make it hard to do this kind of checking.  
In C, it's safe to take locally-declared functions like otherfunc and  
"inject" them into the top-level scope (if there isn't anything else  
there!), so we find them as a last resort.

In C++, we can't inject them into the top-level scope because they  
aren't visible, and we could come up with some weird cases where a  
semantically-correct program would fail if we made them visible.  
Here's a fun one:

	namespace N {
		struct X { };
	}

	void f() {
		int outerfunc(N::X);
	}

	namespace N {
		void outerfunc(X);
	}

	void g(N::X x) {
		outerfunc(x); // okay due to argument-dependent lookup
	}
	
At the call inside g, name lookup of "outerfunc" does not find  
anything. However, once we have the call arguments, argument-dependent  
lookup finds N::outerfunc and calls it.

If we injected f's local declaration of outerfunc into the global  
scope (as we do in C), name lookup would find f's outfunc and argument- 
dependent lookup would find N::outerfunc. We'd then get a failure in  
overload resolution.

I know there are ways around this problem: each namespace (including  
the global scope) could have a map from names to "known but non- 
visible" declarations within that namespace, and we could check that  
as a last resort (e.g., if we're in a case where ADL doesn't work, or  
we didn't find anything even with ADL). However, we have bigger fish  
to fry in C++-land, so I'm not planning to tackle this now.

	- Doug



More information about the cfe-commits mailing list