r180973 - Use attribute argument information to determine when to parse attribute arguments as expressions.

Douglas Gregor dgregor at apple.com
Thu May 2 16:25:32 PDT 2013


Author: dgregor
Date: Thu May  2 18:25:32 2013
New Revision: 180973

URL: http://llvm.org/viewvc/llvm-project?rev=180973&view=rev
Log:
Use attribute argument information to determine when to parse attribute arguments as expressions.

This change partly addresses a heinous problem we have with the
parsing of attribute arguments that are a lone identifier. Previously,
we would end up parsing the 'align' attribute of this as an expression
"(Align)":

 template<unsigned Size, unsigned Align>
 class my_aligned_storage
 {
   __attribute__((align((Align)))) char storage[Size];
 };

while this would parse as a "parameter name" 'Align':

 template<unsigned Size, unsigned Align>
 class my_aligned_storage
 {
   __attribute__((align(Align))) char storage[Size];
 };

The code that handles the alignment attribute would completely ignore
the parameter name, so the while the first of these would do what's
expected, the second would silently be equivalent to

 template<unsigned Size, unsigned Align>
 class my_aligned_storage
 {
   __attribute__((align)) char storage[Size];
 };

i.e., use the maximal alignment rather than the specified alignment.

Address this by sniffing the "Args" provided in the TableGen
description of attributes. If the first argument is "obviously"
something that should be treated as an expression (rather than an
identifier to be matched later), parse it as an expression.

Fixes <rdar://problem/13700933>.


Modified:
    cfe/trunk/include/clang/Parse/CMakeLists.txt
    cfe/trunk/include/clang/Parse/Makefile
    cfe/trunk/lib/Parse/CMakeLists.txt
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/SemaObjC/format-arg-attribute.m
    cfe/trunk/test/SemaTemplate/attributes.cpp
    cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
    cfe/trunk/utils/TableGen/TableGen.cpp
    cfe/trunk/utils/TableGen/TableGenBackends.h

Modified: cfe/trunk/include/clang/Parse/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/CMakeLists.txt?rev=180973&r1=180972&r2=180973&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/CMakeLists.txt (original)
+++ cfe/trunk/include/clang/Parse/CMakeLists.txt Thu May  2 18:25:32 2013
@@ -1,3 +1,8 @@
+clang_tablegen(AttrExprArgs.inc -gen-clang-attr-expr-args-list
+  -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+  SOURCE ../Basic/Attr.td
+  TARGET ClangAttrExprArgs)
+
 clang_tablegen(AttrLateParsed.inc -gen-clang-attr-late-parsed-list
   -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
   SOURCE ../Basic/Attr.td

Modified: cfe/trunk/include/clang/Parse/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Makefile?rev=180973&r1=180972&r2=180973&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Makefile (original)
+++ cfe/trunk/include/clang/Parse/Makefile Thu May  2 18:25:32 2013
@@ -1,11 +1,17 @@
 CLANG_LEVEL := ../../..
 TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
-BUILT_SOURCES = AttrLateParsed.inc
+BUILT_SOURCES = AttrExprArgs.inc AttrLateParsed.inc
 
 TABLEGEN_INC_FILES_COMMON = 1
 
 include $(CLANG_LEVEL)/Makefile
 
+$(ObjDir)/AttrExprArgs.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
+                                   $(ObjDir)/.dir
+	$(Echo) "Building Clang attribute expression arguments table with tblgen"
+	$(Verb) $(ClangTableGen) -gen-clang-attr-expr-args-list -o $(call SYSPATH, $@) \
+		-I $(PROJ_SRC_DIR)/../../ $<
+
 $(ObjDir)/AttrLateParsed.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
                                    $(ObjDir)/.dir
 	$(Echo) "Building Clang attribute late-parsed table with tblgen"

Modified: cfe/trunk/lib/Parse/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/CMakeLists.txt?rev=180973&r1=180972&r2=180973&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/CMakeLists.txt (original)
+++ cfe/trunk/lib/Parse/CMakeLists.txt Thu May  2 18:25:32 2013
@@ -17,6 +17,7 @@ add_clang_library(clangParse
 
 add_dependencies(clangParse
   ClangAttrClasses
+  ClangAttrExprArgs
   ClangAttrLateParsed
   ClangAttrList
   ClangAttrParsedAttrList

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=180973&r1=180972&r2=180973&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu May  2 18:25:32 2013
@@ -178,6 +178,12 @@ void Parser::ParseGNUAttributes(ParsedAt
   }
 }
 
+/// \brief Determine whether the given attribute has all expression arguments.
+static bool attributeHasExprArgs(const IdentifierInfo &II) {
+  return llvm::StringSwitch<bool>(II.getName())
+#include "clang/Parse/AttrExprArgs.inc"
+           .Default(false);
+}
 
 /// Parse the arguments to a parameterized GNU attribute or
 /// a C++11 attribute in "gnu" namespace.
@@ -247,6 +253,10 @@ void Parser::ParseGNUAttributeArgs(Ident
       TypeParsed = true;
       break;
     }
+    // If the attribute has all expression arguments, and not a "parameter",
+    // break out to handle it below.
+    if (attributeHasExprArgs(*AttrName))
+      break;
     ParmName = Tok.getIdentifierInfo();
     ParmLoc = ConsumeToken();
     break;

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=180973&r1=180972&r2=180973&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu May  2 18:25:32 2013
@@ -10633,8 +10633,8 @@ FieldDecl *Sema::CheckFieldDecl(Declarat
   // FIXME: We need to pass in the attributes given an AST
   // representation, not a parser representation.
   if (D) {
-    // FIXME: What to pass instead of TUScope?
-    ProcessDeclAttributes(TUScope, NewFD, *D);
+    // FIXME: The current scope is almost... but not entirely... correct here.
+    ProcessDeclAttributes(getCurScope(), NewFD, *D);
 
     if (NewFD->hasAttrs())
       CheckAlignasUnderalignment(NewFD);

Modified: cfe/trunk/test/SemaObjC/format-arg-attribute.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/format-arg-attribute.m?rev=180973&r1=180972&r2=180973&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/format-arg-attribute.m (original)
+++ cfe/trunk/test/SemaObjC/format-arg-attribute.m Thu May  2 18:25:32 2013
@@ -14,7 +14,7 @@ union u1 { int i; } __attribute__((forma
 enum e1 { E1V0 } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to functions}}
 
 extern NSString *ff3 (const NSString *) __attribute__((format_arg(3-2)));
-extern NSString *ff4 (const NSString *) __attribute__((format_arg(foo))); // expected-error {{attribute takes one argument}}
+extern NSString *ff4 (const NSString *) __attribute__((format_arg(foo))); // expected-error {{use of undeclared identifier 'foo'}}
 
 /* format_arg formats must take and return a string.  */
 extern NSString *fi0 (int) __attribute__((format_arg(1)));  // expected-error {{format argument not a string type}}

Modified: cfe/trunk/test/SemaTemplate/attributes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/attributes.cpp?rev=180973&r1=180972&r2=180973&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/attributes.cpp (original)
+++ cfe/trunk/test/SemaTemplate/attributes.cpp Thu May  2 18:25:32 2013
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=gnu++11 -fsyntax-only -verify %s
 
 namespace attribute_aligned {
   template<int N>
@@ -18,6 +18,26 @@ namespace attribute_aligned {
   check_alignment<2>::t c2;
   check_alignment<3>::t c3; // expected-note 2 {{in instantiation}}
   check_alignment<4>::t c4;
+
+  template<unsigned Size, unsigned Align>
+  class my_aligned_storage
+  {
+    __attribute__((align(Align))) char storage[Size];
+  };
+  
+  template<typename T>
+  class C {
+  public:
+    C() {
+      static_assert(sizeof(t) == sizeof(T), "my_aligned_storage size wrong");
+      static_assert(alignof(t) == alignof(T), "my_aligned_storage align wrong"); // expected-warning{{'alignof' applied to an expression is a GNU extension}}
+    }
+    
+  private:
+    my_aligned_storage<sizeof(T), alignof(T)> t;
+  };
+  
+  C<double> cd;
 }
 
 namespace PR9049 {

Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=180973&r1=180972&r2=180973&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Thu May  2 18:25:32 2013
@@ -971,6 +971,48 @@ void EmitClangAttrClass(RecordKeeper &Re
   OS << "#endif\n";
 }
 
+// Emits the LateParsed property for attributes.
+void EmitClangAttrExprArgsList(RecordKeeper &Records, raw_ostream &OS) {
+  emitSourceFileHeader("llvm::StringSwitch code to match attributes with "
+                       "expression arguments", OS);
+
+  std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+  for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
+       I != E; ++I) {
+    Record &Attr = **I;
+
+    // Determine whether the first argument is something that is always
+    // an expression.
+    std::vector<Record *> Args = Attr.getValueAsListOfDefs("Args");
+    if (Args.empty() || Args[0]->getSuperClasses().empty())
+      continue;
+
+    // Check whether this is one of the argument kinds that implies an
+    // expression.
+    // FIXME: Aligned is weird.
+    if (!llvm::StringSwitch<bool>(Args[0]->getSuperClasses().back()->getName())
+          .Case("AlignedArgument", true)
+          .Case("BoolArgument", true)
+          .Case("DefaultIntArgument", true)
+          .Case("IntArgument", true)
+          .Case("ExprArgument", true)
+          .Case("UnsignedArgument", true)
+          .Case("VariadicUnsignedArgument", true)
+          .Case("VariadicExprArgument", true)
+          .Default(false))
+      continue;
+
+    std::vector<Record*> Spellings = Attr.getValueAsListOfDefs("Spellings");
+
+    for (std::vector<Record*>::const_iterator I = Spellings.begin(),
+         E = Spellings.end(); I != E; ++I) {
+      OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", "
+         << "true" << ")\n";
+    }
+  }
+}
+
 // Emits the class method definitions for attributes.
 void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
   emitSourceFileHeader("Attribute classes' member function definitions", OS);

Modified: cfe/trunk/utils/TableGen/TableGen.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/TableGen.cpp?rev=180973&r1=180972&r2=180973&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/TableGen.cpp (original)
+++ cfe/trunk/utils/TableGen/TableGen.cpp Thu May  2 18:25:32 2013
@@ -24,6 +24,7 @@ using namespace clang;
 
 enum ActionType {
   GenClangAttrClasses,
+  GenClangAttrExprArgsList,
   GenClangAttrImpl,
   GenClangAttrList,
   GenClangAttrPCHRead,
@@ -62,6 +63,10 @@ namespace {
                                "Generate option parser implementation"),
                     clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes",
                                "Generate clang attribute clases"),
+                    clEnumValN(GenClangAttrExprArgsList,
+                               "gen-clang-attr-expr-args-list",
+                               "Generate a clang attribute expression "
+                               "arguments list"),
                     clEnumValN(GenClangAttrImpl, "gen-clang-attr-impl",
                                "Generate clang attribute implementations"),
                     clEnumValN(GenClangAttrList, "gen-clang-attr-list",
@@ -143,6 +148,9 @@ bool ClangTableGenMain(raw_ostream &OS,
   case GenClangAttrClasses:
     EmitClangAttrClass(Records, OS);
     break;
+  case GenClangAttrExprArgsList:
+    EmitClangAttrExprArgsList(Records, OS);
+    break;
   case GenClangAttrImpl:
     EmitClangAttrImpl(Records, OS);
     break;

Modified: cfe/trunk/utils/TableGen/TableGenBackends.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/TableGenBackends.h?rev=180973&r1=180972&r2=180973&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/TableGenBackends.h (original)
+++ cfe/trunk/utils/TableGen/TableGenBackends.h Thu May  2 18:25:32 2013
@@ -30,6 +30,7 @@ void EmitClangASTNodes(RecordKeeper &RK,
                        const std::string &N, const std::string &S);
 
 void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrExprArgsList(RecordKeeper &Records, raw_ostream &OS);
 void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS);
 void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS);
 void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS);





More information about the cfe-commits mailing list