[patch] Knowing if "static" was written or not

The enclosed patch allows to differentiate between those functions and
variables explicitly marked with the keyword static and those functions
or variables that are marked static for semantic reason.

As an example for the C language, the definition of function f below is
static even though the static keyword does not appear:

static void f(void);
void f(void) {} /* this one */

As for C++, here we have an example of a static variable where the static
keyword does not appear:

struct A {
  static int a;
};
int A::a = -1; /* this one */

Currently there seems to be no way to distinguish between a function
that is static because the keyword static is there or because a previous
declaration was marked as static. My patch added few member functions to
FunctionDecl in order to allow making such a distinction.

It is already possible to detect the difference in the variables, but for
sake of clearness I also put a similar member function in VarDecl.

Paolo Bolzoni

patch_clang.tar.gz (3.02 KB)

The enclosed patch allows to differentiate between those functions and
variables explicitly marked with the keyword static and those functions
or variables that are marked static for semantic reason.

As an example for the C language, the definition of function f below is
static even though the static keyword does not appear:

static void f(void);
void f(void) {} /* this one */

As for C++, here we have an example of a static variable where the static
keyword does not appear:

struct A {
static int a;
};
int A::a = -1; /* this one */

Currently there seems to be no way to distinguish between a function
that is static because the keyword static is there or because a previous
declaration was marked as static. My patch added few member functions to
FunctionDecl in order to allow making such a distinction.

It is already possible to detect the difference in the variables, but for
sake of clearness I also put a similar member function in VarDecl.

Paolo Bolzoni

patch_clang.tar.gz (3.02 KB)

The enclosed patch allows to differentiate between those functions and
variables explicitly marked with the keyword static and those functions
or variables that are marked static for semantic reason.

As an example for the C language, the definition of function f below is
static even though the static keyword does not appear:

static void f(void);
void f(void) {} /* this one */

That makes sense.

As for C++, here we have an example of a static variable where the static
keyword does not appear:

struct A {
static int a;
};
int A::a = -1; /* this one */

Well, in this case you aren't allowed to write 'static', so we don't actually need to pass down the 'is static as written' bit in CXXMethodDecl and friends. For example, this isn't necessary:

I followed the hints by Douglas and re-made the patch. I added
getStorageClassAsWritten() in both FunctionDecl and VarDecl. Details about
the fixes wrt previous patch follow.

pb

The enclosed patch allows to differentiate between those functions and
variables explicitly marked with the keyword static and those functions
or variables that are marked static for semantic reason.
[...]
Currently there seems to be no way to distinguish between a function
that is static because the keyword static is there or because a previous
declaration was marked as static. My patch added few member functions to
FunctionDecl in order to allow making such a distinction.

It is already possible to detect the difference in the variables, but for
sake of clearness I also put a similar member function in VarDecl.

I'm curious about why you're focusing on whether "static" was written explicitly rather than tackling the general problem of "what storage specifier was actually written?". For example, one could have:

      static int i;
      extern int i;

where the semantic storage specifier of the second "i" is "static" but the storage specifier as written is "extern". Wouldn't it be more valuable to add, to both FunctionDecl and VarDecl, a

      StorageClass getStorageClassAsWritten() const;

?

It is indeed more valuable, I just did not thought about this case.

As for C++, here we have an example of a static variable where the static
keyword does not appear:

struct A {
static int a;
};
int A::a = -1; /* this one */

Well, in this case you aren't allowed to write 'static', so we don't actually need to pass down the 'is static as written' bit in CXXMethodDecl and friends. For example, this isn't necessary:

[old patch piece omitted]

And CXXConversionDecl, CXXConstructorDecl, and CXXDestructorDecl nodes will never need "static as written" bits, because they can never be static.

Even though getStorageClassAsWritten() will never return 'static' on a
correct program, it might return 'extern', since it is possible to do
something such as the following:

struct A {
   operator void*();
};
extern A::operator void*() { return 0; }

One last comment...

Index: include/clang/Parse/DeclSpec.h

--- include/clang/Parse/DeclSpec.h (revision 95203)
+++ include/clang/Parse/DeclSpec.h (working copy)
[...]
@@ -238,6 +240,11 @@
[...]
+ bool isStaticSpecified() const { return SCS_static_specified; }
+ SourceLocation getStaticSpecLoc() const { return isStaticSpecified()
+ ? StorageClassSpecLoc
+ : SourceLocation(); }
+
[...]

I don't understand why this is needed. The DeclSpec will only have a single storage specifier; the one that was written in the source, along with the location of that storage specifier. It's only when we get into merging function or variable declarations that we change the effective storage class on the AST (but not in the DeclSpec).

You are right, I misunderstood a few details in DeclSpec.
Now this should be corrected.

pb

patch.tar.gz (8.78 KB)