[cfe-dev] [patch] Knowing if "static" was written or not

Douglas Gregor dgregor at apple.com
Fri Feb 12 10:03:53 PST 2010


On Feb 8, 2010, at 12:25 AM, Paolo Bolzoni wrote:

> 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:

===================================================================
--- include/clang/AST/DeclCXX.h (revision 95203)
+++ include/clang/AST/DeclCXX.h (working copy)
@@ -844,16 +844,17 @@
 protected:
   CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation L,
                 DeclarationName N, QualType T, TypeSourceInfo *TInfo,
-                bool isStatic, bool isInline)
+                bool isStatic, bool isInline, bool isStaticAsWritten)
     : FunctionDecl(DK, RD, L, N, T, TInfo, (isStatic ? Static : None),-                   isInline) {}
+                   isInline, isStaticAsWritten) {}
 
 public:
   static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD,
                               SourceLocation L, DeclarationName N,
                               QualType T, TypeSourceInfo *TInfo,
                               bool isStatic = false,
-                              bool isInline = false);
+                              bool isInline = false,
+                              bool isStaticAsWritten = false);

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

> 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;

?

One last comment...

Index: include/clang/Parse/DeclSpec.h
===================================================================
--- include/clang/Parse/DeclSpec.h      (revision 95203)
+++ include/clang/Parse/DeclSpec.h      (working copy)
@@ -200,6 +200,7 @@
   SourceLocation FriendLoc, ConstexprLoc;
 
   WrittenBuiltinSpecs writtenBS;
+  bool SCS_static_specified : 1;
   void SaveWrittenBuiltinSpecs();
 
   DeclSpec(const DeclSpec&);       // DO NOT IMPLEMENT
@@ -224,7 +225,8 @@
       AttrList(0),
       ProtocolQualifiers(0),
       NumProtocolQualifiers(0),
-      ProtocolLocs(0) {
+      ProtocolLocs(0),
+      SCS_static_specified(false) {
   }
   ~DeclSpec() {
     delete AttrList;
@@ -238,6 +240,11 @@
   SourceLocation getStorageClassSpecLoc() const { return StorageClassSpecLoc; }
   SourceLocation getThreadSpecLoc() const { return SCS_threadLoc; }
 
+  bool isStaticSpecified() const { return SCS_static_specified; }
+  SourceLocation getStaticSpecLoc() const { return isStaticSpecified()
+                                            ? StorageClassSpecLoc
+                                            : SourceLocation(); }
+
   void ClearStorageClassSpecs() {
     StorageClassSpec     = DeclSpec::SCS_unspecified;
     SCS_thread_specified = false;

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).

	- Doug



More information about the cfe-dev mailing list