[cfe-dev] time of inline assembler evaluation in template specialization

Douglas Gregor dgregor at apple.com
Fri Jun 24 07:47:21 PDT 2011


On Jun 24, 2011, at 6:09 AM, Titus von Boxberg wrote:

> Am Fr, 24.06.2011, 11:51 schrieb Sebastian Redl:
>> On 24.06.2011 10:09, Titus von Boxberg wrote:
>>> There is no "ill formed", "invalid" or whatsoever bad C++ code in my example.
>> There is ill-formed use of a GCC/Clang extension: you have a clobber
>> list that contains registers not valid for the current platform. The
>> fact that it happens to be in an inline function of a template
>> specialization is irrelevant here.
> No, it is relevant here because that's the use case.

The "use case" argument is separate from the "it's a template" argument.

>> 
>>> It's like in any template instantiation / specialization.
>>> It only works because the right (specialized) template code gets selected and emitted.
>> That's not how templates work.
> How else should they work?
> std::copy is perfectly valid until I instantiate it with e.g. an int instead of
> something which has an interface of an iterator.
> Analogous to this code.

It is not analogous.

In your std::copy() example, the expressions that become ill-formed when instantiating std::copy with an 'int' were valid at template definition time, because they depend on a template parameter. For example, this template definition is fine:

	template<typename T> void f1(T x, T y) { x + y; } // x + y depends on a template parameter

but instantiating it with int* would make the program ill-formed. In the other hand, this template definition

	template<typename T> void f1(int* x, int *y) { x + y; } // ill-formed, x + y doesn't depend on a template parameter

is ill-formed per C++ 14.6p8 (since there are no valid instantiations of this template), but that implementations are not *required* to diagnose the problem.

Note that with your asm example:

	asm("ldr r4,=1\n\t" ::: "r4");

the clobber list does not depend on a template parameter, so if we extend C++ standard semantics to the "asm" statement in the natural way, this asm statement is ill-formed regardless of whether it occurs in a template or not.

That's the first technical issue with the "it's a template" argument.

The second technical issue with the "it's a template" argument is that your example is in fact not a template:

template<>
struct A<8> {
 void f(void) {
   asm("ldr r4,=1\n\t" ::: "r4");
 }
};

That's a class template specialization, but it's not a template because there are no template parameters. Hence, the compiler is required to fully type-check the definition of this class template specialization and it's members, so the discussion above is moot.

>>> All I want to say is:
>>> Doing it the gcc way is what I'd suggest for clang.
>> So you don't want to know about bad asm constraints if you just run an
>> -fsyntax-only check over the file? Because that's what delaying the
>> check to code generation means. Well, I want to get an error then. So I
>> vote for not delaying the check.
> You're not really trying to tell me that an intended use
> case of clang is to fsyntax-only-check asm() register declarations?

There's an important invariant here that if a program passes semantic analysis, it builds a well-formed abstract syntax tree (AST). At this point, generating code from that AST should always succeed, and other tools and analyses know they are working with a well-formed program. At this point, code generation should not be able to fail.

>>> The sense to accept this code is because one gains the option of
>>> using template specialization instead of having to rely on the preprocessor
>>> to select the right (assembly) code which is perfectly reasonable.
>> What makes the preprocessor a worse choice than templates here?
> First, this is a matter of taste, and thus is not really an argument.

Opinion is a valid argument; it just has the unfortunate aspect of allowing everyone to be right and still disagree :)

There are two important pieces here: (1) using the preprocessor is a solution, and (2) you find it cleaner to use template specialization.

> Second because there *is* existing code which relies on gcc's (consistent)
> different levels of inline assembly checking.

This is a (differ) valid argument: that Clang should accept this code to be compatible with GCC.

GCC compatibility is a compelling argument, but we always weigh the pros and cons of a particular GCC extension.

How much code will be broken by this? 
	Apparently very little, since this is the only report we've seen about this problem since we turned on the integrated assembler more than a year ago.

Is the code that will be broken reasonable?
	This code is (intentionally) ill-formed code that GCC only accepts because it does checking of the clobbers at code generation time. This has more of the characteristics of a GCC bug than a language feature.

Is accepting this code detrimental to the language or other users?
	Yes, since moving this checking to code generation time makes Clang accept ill-formed programs. For example, users in an environment that provide type-checking via Clang (without using code generation) would no longer diagnose errors in asm clobbers.

Is there a workaround?
	Yes, through the use of the preprocessor.


This extension fails basically all of the criteria we use to decide when to implement an extension in Clang.

	- Doug




More information about the cfe-dev mailing list