Internal type as a template argument - c++

ISO 98/03 standard (section 14.3.1) seems to forbid using a type with internal linkage as a template parameter. (See example below.) The C++11 standard does not.
G++ - using the old standard - is allowing it.
Am I misreading the 03 standard, or is g++ just letting this slide?
namespace
{
struct hidden { };
}
template<typename T>
struct S
{
T t;
};
int main()
{
S<hidden> s;
return 0;
}

You're correct that C++03 doesn't allow using a type with internal linkage as a template type parameter, while C++11 does.
I seem to recall, however, that definitions inside the anonymous namespace still have external linkage.
Yup, section 3.5 [basic.link] says
A name having namespace scope (3.3.5) has internal linkage if it is the name of
an object, reference, function or function template that is explicitly declared static or,
an object or reference that is explicitly declared const and neither explicitly declared extern nor previously declared to have external linkage; or
a data member of an anonymous union.
A name having namespace scope has external linkage if it is the name of
an object or reference, unless it has internal linkage; or
a function, unless it has internal linkage; or
a named class (clause 9), or an unnamed class defined in a typedef declaration in which the class has the typedef name for linkage purposes (7.1.3); or
a named enumeration (7.2), or an unnamed enumeration defined in a typedef declaration in which the enumeration has the typedef name for linkage purposes (7.1.3); or
an enumerator belonging to an enumeration with external linkage; or
a template, unless it is a function template that has internal linkage (clause 14); or
a namespace (7.3), unless it is declared within an unnamed namespace.
You have a named class at namespace scope, it has external linkage.
And the footnote on the bottom of page 115 of ISO/IEC 14882:2003 clarifies:
Although entities in an unnamed namespace might have external linkage, they are effectively qualified by a name unique to their translation unit and therefore can never be seen from any other translation unit.
If you have another version, try looking in section 7.3.1.1 [namespace.unnamed]

That's not a valid example of the rule. The hidden class in your example has external linkage. (It has a compiler-generated unique name such that nothing outside the current translation unit can actually link with it, but it's still external.)
The standard gives an example of a local type:
template <class T> class X { /* ... */ };
void f()
{
struct S { /* ... */ };
X<S> x3; // error: local type used as template-argument
X<S*> x4; // error: pointer to local type used as template-argument
}

Related

Type alias with same name as type

Is it valid C++ ?
#include <iostream>
class Test {
struct Inner {
};
public:
using Inner = struct Inner; // Alias with same name as type
};
int main(int argc, const char * argv[]) {
static_assert(std::is_pod<Test::Inner>::value, "");
return 0;
}
Compile fine with clang but not with GCC / Visual C++ ("Inner is private..." error message)
GCC and Visual C++ are correct.
Indeed you can use using to in effect change the access of a member, e.g.
using Inner_ = Inner;
with
static_assert(std::is_pod<Test::Inner_>::value, "");
in the function.
But in the case where the type alias has the same name as the member, C++ requires that the scope resolution operator looks up the member. So in your case Test::Inner refers to the actual member rather than to the using and compilation should therefore fail as it's private.
See https://en.cppreference.com/w/cpp/language/qualified_lookup, and in particular
Qualified lookup within the scope of a namespace N first considers all
declarations that are located in N and all declarations that are
located in the inline namespace members of N (and, transitively, in
their inline namespace members). If there are no declarations in that
set then it considers declarations in all namespaces named by
using-directives found in N and in all transitive inline namespace
members of N
P1787R6: Declarations and where to find them, merged into C++23 draft, seems to favor Clang's behavior:
[basic.lookup]
In certain contexts, only certain kinds of declarations are included. After any such restriction, any declarations of classes or enumerations are discarded if any other declarations are found. [Note: A type (but not a typedef-name or template) is therefore hidden by any other entity in its scope. — end note] However, if a lookup is type-only, only declarations of types and templates whose specializations are types are considered; furthermore, if declarations of a typedef-name and of the type to which it refers are found, the declaration of the typedef-name is discarded instead of the type declaration.
So the declaration of struct Inner is discarded, because the alias-declaration is found. (One can put Inner into type-only context — Test::struct Inner — and it will refer to the struct Inner declaration, per the second part of the paragraph).

How to fix a -Wsubobject-linkage warning?

I'm getting a gcc warning for code which compiles fine and warning free in clang and VC++, so I assume it's something gcc specific. This is the code:
namespace myns {
using TokenList = std::vector<size_t>;
using RuleList = std::vector<size_t>;
using RulePathPair = std::pair<size_t, TokenList>;
using CandidatesCollection = struct { std::map<size_t, TokenList> tokens; std::set<RulePathPair> rules; };
class A {
private:
CandidatesCollection _candidates;
};
} // namespace myns
and the warning is:
warning: 'myns::A' has a field 'myns::A::_candidates' whose type has no linkage [-Wsubobject-linkage]
What does this mean and how to get rid of the warning?
I believe the compiler might be wrong here: the type referred to by CandidatesCollection should in fact have external linkage.
[basic.link]/4 ...A name having namespace scope that has not been given internal linkage above has the same linkage as the enclosing namespace if it is the name of
...
(4.3) — a named class (Clause 9), or an unnamed class defined in a typedef declaration in which the class has the typedef name for linkage purposes (7.1.3); ...
[dcl.typedef]/9 If the typedef declaration defines an unnamed class (or enum), the first typedef-name declared by the declaration to be that class type (or enum type) is used to denote the class type (or enum type) for linkage purposes only (3.5). [ Example:
typedef struct { } *ps, S; // S is the class name for linkage purposes
—end example ]
Thus, if CandidatesCollection were defined as
typedef struct { ... } CandidatesCollection;
these two passages make it clear that the class named by CandidatesCollection would happily have external linkage.
Then there's
[dcl.typedef]/2 A typedef-name can also be introduced by an alias-declaration. The identifier following the using keyword becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that typedef-name. It has the same semantics as if it were introduced by the typedef specifier.
Emphasis mine. This suggests that the name introduced by using should give the unnamed class "the name for linkage purposes" just as well as the equivalent typedef declaration, thereby ensuring that the class has external linkage.

Example of entity declared in a anonymous namespace that has external linkage

Given the statements below (emphasis mine) in §3.5/4 and in the Note [94] in §7.3.1.1/1, I'd like to have one single example of an entity declared in a unnamed namespace that has external linkage.
§3.5/4
An unnamed namespace or a namespace declared directly or indirectly
within an unnamed namespace has internal linkage. All other namespaces
have external linkage. A name having namespace scope that has not been
given internal linkage above has the same linkage as the enclosing
namespace if it is the name of
a variable; or
a function; or
a named class (Clause 9), or an unnamed class defined in a typedef declaration in which the class has the typedef name for linkage
purposes (7.1.3); or
a named enumeration (7.2), or an unnamed enumeration defined in a typedef declaration in which the enumeration has the typedef name for
linkage purposes (7.1.3); or
an enumerator belonging to an enumeration with linkage; or
a template.
Note [94] on §7.3.1.1/1:
Although entities in an unnamed namespace might have external linkage,
they are effectively qualified by a name unique to their translation
unit and therefore can never be seen from any other translation unit.
You are looking at a defect in the standard.
The change that makes unnamed namespace members have internal linkage happened fairly late in the C++11 standardization process, in November 2010 (CWG issue 1113). As a result, a number of places in the standard needs to be changed, but weren't. One of which is the footnote you quoted.
CWG issue 1603, currently in "ready" status (read: the resolution is likely to be adopted at the next committee meeting), will fix this and a number of other issues related to giving internal linkage to unnamed namespace members.
It's a good question because it's difficult to demonstrate. We can take advantage of other rules in the C++ Standard to show that a variable in an anonymous namespace can have external linkage.
Templating on an int* with external linkage will succeed while templating on an int* with internal linkage will fail.
#include <iostream>
namespace {
// not externally linked, won't compile
// const int i = 5;
// external linkage, compiles
extern int i;
int i = 5;
}
template<int* int_ptr>
struct temp_on_extern_linked_int {
temp_on_extern_linked_int() {
std::cout << *int_ptr << std::endl;
}
};
int main() {
temp_on_extern_linked_int<&i>();
}
As shown the program compiles and runs.
$ g++-4.8 main.cpp -o main
$ ./main
5
Uncommenting the other definition of i causes the compile to fail.
$ g++-4.8 main.cpp -o main
main.cpp: In function 'int main()':
main.cpp:17:30: error: '& {anonymous}::i' is not a valid template argument of
type 'int*' because '{anonymous}::i' does not have external linkage
temp_on_extern_linked_int<&i>();
^
The compiler is quite helpful. It explicitly states that because i doesn't have external linkage the compile failed.
The commented definition of i has internal linkage because it is qualified const without extern. (§3.4.6)
Variables at namespace scope that are declared const and not extern have internal linkage.
Part of the trick is not compiling as C++11.
Why did C++03 require template parameters to have external linkage?
For example
#include <iostream>
namespace
{
extern int x = 10;
void f( int y )
{
extern int x;
std::cout << x + y << std::endl;
}
}
int main()
{
int y = 15;
f( y );
return 0;
}
According to the C++ Standard
6 The name of a function declared in block scope and the name of a
variable declared by a block scope extern declaration have linkage. If
there is a visible declaration of an entity with linkage having the
same name and type, ignoring entities declared outside the innermost
enclosing namespace scope, the block scope declaration declares that
same entity and receives the linkage of the previous declaration. If
there is more than one such matching entity, the program is
ill-formed. Otherwise, if no matching entity is found, the block scope
entity receives external linkage

clang error: non-type template argument refers to function that does not have linkage -- bug?

I have some very simple (C++11) code which the latest clang (version 3.4 trunk 187493) fails to compile, but GCC compiles fine.
The code (below) instantiates the function-template foo with the function-local type Bar and then tries to use its address as a non-type template parameter for the class-template Func:
template<void(*FUNC_PTR)(void)>
struct Func {};
template<typename T> extern inline
void foo() {
using Foo = Func<foo<T>>;
}
int main() {
struct Bar {}; // function-local type
foo<Bar>();
return 0;
}
clang emits the following error:
error: non-type template argument refers to function 'foo' that
does not have linkage
However, if I move type Bar to global scope (by taking it out of the function), then clang compiles it fine, proving the issue is with the type being function-local.
So is clang correct to emit this error, or does the standard not support this (in which case GCC is being too lenient by allowing it)?
EDIT #1 : To be clear, this is not a duplicate of this question since the 'cannot use local types as template parameters' restriction was removed in C++11. However, it's still unclear if there are linkage implications involved with using a local type, and whether clang is correct or not in emitting this error.
EDIT #2 : It has been determined that clang was correct to emit the error for the above code (see answer from #jxh), but that it incorrectly also emits an error for the following code (with using declaration moved from foo<Bar>() scope to main() scope):
template<void(*FUNC_PTR)(void)>
struct Func {};
template<typename T> extern inline
void foo() {}
int main() {
struct Bar {};
using F = Func<foo<Bar>>;
return 0;
}
By definition of no linkage in C++.11 §3.5 Program and linkage ¶2, I originally believed foo<Bar> has no linkage since it cannot be referred to by name by any other scope except that which defined the type Bar (ie, main()). However, this is not correct. This is because the definition of a name with external linkage is described as:
When a name has external linkage, the entity it denotes can be referred to by names from scopes of other translation units or from other scopes of the same translation unit.
And for a template function, this will always be the case. This is because there is one other scope from which the name can be referred. Namely, the template function can refer to itself. Therefore, foo<Bar> has external linkage. zneak's answer, EDIT 2, has an e-mail thread with the clang developers confirming that foo<Bar> should have external linkage.
Thus, from C++.11 §14.3.2 Template non-type arguments ¶1:
A template-argument for a non-type, non-template template-parameter shall be one of: ...
a constant expression (5.19) that designates the address of an object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as &id-expression, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; ...
The most relevant bullet is the third bullet. Since foo<bar> has external linkage, passing it as a non-type template-parameter should be fine.
I'm late to the party, but standard says that type-local functions don't have linkage (§3.5:8):
Names not covered by these rules have no linkage. Moreover, except as noted, a name declared at block scope (3.3.3) has no linkage.
Same section goes on to say:
A type without linkage shall not be used as the type of a variable or function with external linkage unless
the entity has C language linkage (7.5), or
the entity is declared within an unnamed namespace (7.3.1), or
the entity is not odr-used (3.2) or is defined in the same translation unit.
And, as a matter of fact, Clang will allow this:
namespace
{
template<void (*FUNC_PTR)(void)>
struct Func {};
template<typename T>
void foo() {}
}
int main() {
struct Bar {}; // function-local type
Func<foo<Bar>> x;
}
And will reject it without the anonymous namespace.
EDIT 1: As jxh notes, the names are also defined in the same translation unit, so I'm not sure what to think of this one.
EDIT 2: The guys at clang confirm it's a bug.

Does static object in a template function have linkage?

This question refers to my previous question: clang does not compile my code, but g++ does. From my research, the issue at stake boils down to linkage, does the static variable data have linkage in the sample below (it compiles with g++-4.8.1)? How come it has linkage (I would not otherwise be able to instantiate with a non-type template parameter)?
template <int const* ptr>
void foo()
{
}
typedef void (*func_type)();
template <int = 0>
void run_me()
{
static int data;
func_type const f1 = foo<&data>;
// auto f2 = foo<&data>; // doesn't work with gcc
// foo<&data>(); // doesn't work with gcc
}
int main(int, char*[])
{
run_me();
return 0;
}
Obligatory quote from the standard:
A template-argument for a non-type, non-template template-parameter shall be one of:
...
— a constant expression (5.19) that designates the address of an object with static storage duration and
external or internal linkage or a function with external or internal linkage, including function templates
and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as
& id-expression, except that the & may be omitted if the name refers to a function or array and shall
be omitted if the corresponding template-parameter is a reference; or
...
Surely a static variable declared in a function (whether or not it is a template function) has no linkage.
§3.5 para. 8: "except as noted, a name declared at block scope (3.3.3) has no linkage"
The only exceptions listed in that clause, as far as I can see, are provided in para. 6: "The name of a function declared in block scope and the name of a variable declared by a block scope extern declaration have linkage."
However, it's possible that 14.3.2 might be loosened at some point.
Daniel Krügler submitted DR 1451 on 2012-02-01:
According to 14.3.2 [temp.arg.nontype] paragraph 1 bullet 3, only objects with linkage can be used to form non-type template arguments. Is this restriction still needed? It would be convenient to use block-scope objects as template arguments.
The DR was closed on the basis that it is an extension request and should be dealt with by the Evolution Working Group. It seems to have been included in n3413, "Allowing arbitrary literal types for non-type template parameters".
So it's certainly conceivable that one or more C++ compilers might choose to implement a looser restriction on non-type template parameters.