]> granicus.if.org Git - clang/commitdiff
Use attribute argument information to determine when to parse attribute arguments...
authorDouglas Gregor <dgregor@apple.com>
Thu, 2 May 2013 23:08:12 +0000 (23:08 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 2 May 2013 23:08:12 +0000 (23:08 +0000)
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>.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@180970 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/Attr.td
include/clang/Parse/CMakeLists.txt
include/clang/Parse/Makefile
lib/Parse/CMakeLists.txt
lib/Parse/ParseDecl.cpp
lib/Sema/SemaDecl.cpp
test/SemaObjC/format-arg-attribute.m
test/SemaTemplate/attributes.cpp
utils/TableGen/ClangAttrEmitter.cpp
utils/TableGen/TableGen.cpp
utils/TableGen/TableGenBackends.h

index 441a79a23b263ca5c802f820f3fdbd02d25c7430..8d825ad8f2a09034358aeab64656893d328e1a6c 100644 (file)
@@ -152,7 +152,7 @@ def AddressSpace : Attr {
 
 def Alias : InheritableAttr {
   let Spellings = [GNU<"alias">, CXX11<"gnu", "alias">];
-  let Args = [StringArgument<"Aliasee">];
+  let Args = [IdentifierArgument<"Aliasee">];
 }
 
 def Aligned : InheritableAttr {
@@ -184,7 +184,7 @@ def AlwaysInline : InheritableAttr {
 def TLSModel : InheritableAttr {
   let Spellings = [GNU<"tls_model">, CXX11<"gnu", "tls_model">];
   let Subjects = [Var];
-  let Args = [StringArgument<"Model">];
+  let Args = [IdentifierArgument<"Model">];
 }
 
 def AnalyzerNoReturn : InheritableAttr {
@@ -373,7 +373,7 @@ def MinSize : InheritableAttr {
 
 def Format : InheritableAttr {
   let Spellings = [GNU<"format">, CXX11<"gnu", "format">];
-  let Args = [StringArgument<"Type">, IntArgument<"FormatIdx">,
+  let Args = [IdentifierArgument<"Type">, IntArgument<"FormatIdx">,
               IntArgument<"FirstArg">];
 }
 
index d1ff2abfee66ab4cd68016cd2315618e0a8aec51..d20708e58c55d73f2b7d62e1fb00b5490fef711a 100644 (file)
@@ -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
index 296892c5b6edfd024ac44af841e544106d877667..fb63175ba9b39a22ade4679f1630de81b0f9205a 100644 (file)
@@ -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"
index 939998ecb1af939509c58888b74784842f783fc1..01c0694d0359e20325be7eb38fe5fcb98cd16331 100644 (file)
@@ -17,6 +17,7 @@ add_clang_library(clangParse
 
 add_dependencies(clangParse
   ClangAttrClasses
+  ClangAttrExprArgs
   ClangAttrLateParsed
   ClangAttrList
   ClangAttrParsedAttrList
index 2f0c1a3b8da70186ab29ebde776a811ab7dd9872..a4cec8c2575c172c27f21a42e55db1d5d7c946f6 100644 (file)
@@ -178,6 +178,12 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
   }
 }
 
+/// \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(IdentifierInfo *AttrName,
       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;
index 1aab5c669f970d468155519408bb55226d591b4f..cc8cb4a3951afa333e985de2b07e5069690614c4 100644 (file)
@@ -10633,8 +10633,8 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
   // 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);
index 6edb8fd99b31c51c5fd52fd7cf3601410c965303..dede433f37a2ab541c0bab40417eaa8b01be95f3 100644 (file)
@@ -14,7 +14,7 @@ union u1 { int i; } __attribute__((format_arg(1)));  // expected-warning {{'form
 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}}
index 495f4a7ad3892d00361188a26c6794afefb0e567..5a06a706aa84fea4e96e9c53698dcaa606179d2f 100644 (file)
@@ -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 {
index 7c8603fc6c318927ae792e8039cd0731c6987ebf..36de06e2df69f1c17d89547132a3256af686d74d 100644 (file)
@@ -971,6 +971,49 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
   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("StringArgument", 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);
index 3df8940b055c271ccfdbfcafc77041ad56326588..12e1c47725e152d92c74a2bce5ddf9dca9426c2a 100644 (file)
@@ -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, RecordKeeper &Records) {
   case GenClangAttrClasses:
     EmitClangAttrClass(Records, OS);
     break;
+  case GenClangAttrExprArgsList:
+    EmitClangAttrExprArgsList(Records, OS);
+    break;
   case GenClangAttrImpl:
     EmitClangAttrImpl(Records, OS);
     break;
index 03708b6a7660b2539e4acc9e5def0c82f733b225..0ff33d775cc064102ad1ff08b4d9f4f073bb6320 100644 (file)
@@ -30,6 +30,7 @@ void EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS,
                        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);