r251469 - Add the ability to define "fake" arguments on attributes.

John McCall via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 27 17:17:34 PDT 2015


Author: rjmccall
Date: Tue Oct 27 19:17:34 2015
New Revision: 251469

URL: http://llvm.org/viewvc/llvm-project?rev=251469&view=rev
Log:
Add the ability to define "fake" arguments on attributes.

Fake arguments are automatically handled for serialization, cloning,
and other representational tasks, but aren't included in pretty-printing
or parsing (should we eventually ever automate that).

This is chiefly useful for attributes that can be written by the
user, but which are also frequently synthesized by the compiler,
and which we'd like to remember details of the synthesis for.
As a simple example, use this to narrow the cases in which we were
generating a specialized note for implicitly unavailable declarations.

Modified:
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/test/SemaObjC/arc-system-header.m
    cfe/trunk/test/SemaObjCXX/arc-system-header.mm
    cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=251469&r1=251468&r2=251469&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Tue Oct 27 19:17:34 2015
@@ -129,9 +129,10 @@ def HasFunctionProto : SubsetSubject<Dec
                                        isa<BlockDecl>(S)}]>;
 
 // A single argument to an attribute
-class Argument<string name, bit optional> {
+class Argument<string name, bit optional, bit fake = 0> {
   string Name = name;
   bit Optional = optional;
+  bit Fake = fake;
 }
 
 class BoolArgument<string name, bit opt = 0> : Argument<name, opt>;
@@ -167,7 +168,8 @@ class DefaultIntArgument<string name, in
 // This argument is more complex, it includes the enumerator type name,
 // a list of strings to accept, and a list of enumerators to map them to.
 class EnumArgument<string name, string type, list<string> values,
-                   list<string> enums, bit opt = 0> : Argument<name, opt> {
+                   list<string> enums, bit opt = 0, bit fake = 0>
+    : Argument<name, opt, fake> {
   string Type = type;
   list<string> Values = values;
   list<string> Enums = enums;
@@ -1350,7 +1352,10 @@ def TransparentUnion : InheritableAttr {
 
 def Unavailable : InheritableAttr {
   let Spellings = [GNU<"unavailable">];
-  let Args = [StringArgument<"Message", 1>];
+  let Args = [StringArgument<"Message", 1>,
+              EnumArgument<"ImplicitSource", "ImplicitSourceKind",
+                           ["none", "forbiddenType"],
+                           ["ISK_None", "ISK_ForbiddenType"], 1, /*fake*/ 1>];
   let Documentation = [Undocumented];
 }
 

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=251469&r1=251468&r2=251469&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Oct 27 19:17:34 2015
@@ -5378,7 +5378,7 @@ static void handleDelayedForbiddenType(S
   llvm::StringRef explanation;
   if (decl && isForbiddenTypeAllowed(S, decl, diag, explanation)) {
     decl->addAttr(UnavailableAttr::CreateImplicit(S.Context, explanation,
-                                                  diag.Loc));
+                                UnavailableAttr::ISK_ForbiddenType, diag.Loc));
     return;
   }
   if (S.getLangOpts().ObjCAutoRefCount)
@@ -5464,7 +5464,8 @@ static void DoEmitAvailabilityWarning(Se
 
     if (!Message.empty()) {
       if (auto attr = D->getAttr<UnavailableAttr>())
-        if (attr->isImplicit())
+        if (attr->isImplicit() &&
+            attr->getImplicitSource() == UnavailableAttr::ISK_ForbiddenType)
           diag_available_here = diag::note_unavailability_inferred_here;
     }
 

Modified: cfe/trunk/test/SemaObjC/arc-system-header.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-system-header.m?rev=251469&r1=251468&r2=251469&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/arc-system-header.m (original)
+++ cfe/trunk/test/SemaObjC/arc-system-header.m Tue Oct 27 19:17:34 2015
@@ -7,8 +7,8 @@
 void test(id op, void *cp) {
   cp = test0(op); // expected-error {{'test0' is unavailable: converts between Objective-C and C pointers in -fobjc-arc}}
   cp = *test1(&op); // expected-error {{'test1' is unavailable: converts between Objective-C and C pointers in -fobjc-arc}}
-// expected-note at arc-system-header.h:1 {{unsupported declaration here}}
-// expected-note at arc-system-header.h:5 {{unsupported declaration here}}
+// expected-note at arc-system-header.h:1 {{'test0' has been explicitly marked unavailable here}}
+// expected-note at arc-system-header.h:5 {{'test1' has been explicitly marked unavailable here}}
 }
 
 void test3(struct Test3 *p) {
@@ -24,7 +24,7 @@ void test4(Test4 *p) {
 
 void test5(struct Test5 *p) {
   p->field = 0; // expected-error {{'field' is unavailable: this system field has retaining ownership}}
-                // expected-note at arc-system-header.h:25 {{unsupported declaration here}}
+                // expected-note at arc-system-header.h:25 {{'field' has been explicitly marked unavailable here}}
 }
 
 id test6() {

Modified: cfe/trunk/test/SemaObjCXX/arc-system-header.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-system-header.mm?rev=251469&r1=251468&r2=251469&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-system-header.mm (original)
+++ cfe/trunk/test/SemaObjCXX/arc-system-header.mm Tue Oct 27 19:17:34 2015
@@ -6,4 +6,4 @@ void f(A* a) {
   a->data.void_ptr = 0;
   a->data.a_b.b = 0; // expected-error{{'a_b' is unavailable: this system field has retaining ownership}}
 }
-// expected-note at arc-system-header.h:10{{unsupported declaration here}}
+// expected-note at arc-system-header.h:10{{'a_b' has been explicitly marked unavailable here}}

Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=251469&r1=251468&r2=251469&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Tue Oct 27 19:17:34 2015
@@ -166,11 +166,12 @@ namespace {
     std::string lowerName, upperName;
     StringRef attrName;
     bool isOpt;
+    bool Fake;
 
   public:
     Argument(const Record &Arg, StringRef Attr)
       : lowerName(Arg.getValueAsString("Name")), upperName(lowerName),
-        attrName(Attr), isOpt(false) {
+        attrName(Attr), isOpt(false), Fake(false) {
       if (!lowerName.empty()) {
         lowerName[0] = std::tolower(lowerName[0]);
         upperName[0] = std::toupper(upperName[0]);
@@ -185,6 +186,9 @@ namespace {
     bool isOptional() const { return isOpt; }
     void setOptional(bool set) { isOpt = set; }
 
+    bool isFake() const { return Fake; }
+    void setFake(bool fake) { Fake = fake; }
+
     // These functions print the argument contents formatted in different ways.
     virtual void writeAccessors(raw_ostream &OS) const = 0;
     virtual void writeAccessorDefinitions(raw_ostream &OS) const {}
@@ -1078,6 +1082,9 @@ createArgument(const Record &Arg, String
   if (Ptr && Arg.getValueAsBit("Optional"))
     Ptr->setOptional(true);
 
+  if (Ptr && Arg.getValueAsBit("Fake"))
+    Ptr->setFake(true);
+
   return Ptr;
 }
 
@@ -1186,23 +1193,33 @@ writePrettyPrintFunction(Record &R,
       continue;
     }
 
+    // Fake arguments aren't part of the parsed form and should not be
+    // pretty-printed.
+    bool hasNonFakeArgs = false;
+    for (const auto &arg : Args) {
+      if (arg->isFake()) continue;
+      hasNonFakeArgs = true;
+    }
+
     // FIXME: always printing the parenthesis isn't the correct behavior for
     // attributes which have optional arguments that were not provided. For
     // instance: __attribute__((aligned)) will be pretty printed as
     // __attribute__((aligned())). The logic should check whether there is only
     // a single argument, and if it is optional, whether it has been provided.
-    if (!Args.empty())
+    if (hasNonFakeArgs)
       OS << "(";
     if (Spelling == "availability") {
       writeAvailabilityValue(OS);
     } else {
-      for (auto I = Args.begin(), E = Args.end(); I != E; ++ I) {
-        if (I != Args.begin()) OS << ", ";
-        (*I)->writeValue(OS);
+      unsigned index = 0;
+      for (const auto &arg : Args) {
+        if (arg->isFake()) continue;
+        if (index++) OS << ", ";
+        arg->writeValue(OS);
       }
     }
 
-    if (!Args.empty())
+    if (hasNonFakeArgs)
       OS << ")";
     OS << Suffix + "\";\n";
 
@@ -1474,10 +1491,19 @@ void EmitClangAttrClass(RecordKeeper &Re
     std::vector<std::unique_ptr<Argument>> Args;
     Args.reserve(ArgRecords.size());
 
+    bool HasOptArg = false;
+    bool HasFakeArg = false;
     for (const auto *ArgRecord : ArgRecords) {
       Args.emplace_back(createArgument(*ArgRecord, R.getName()));
       Args.back()->writeDeclarations(OS);
       OS << "\n\n";
+
+      // For these purposes, fake takes priority over optional.
+      if (Args.back()->isFake()) {
+        HasFakeArg = true;
+      } else if (Args.back()->isOptional()) {
+        HasOptArg = true;
+      }
     }
 
     OS << "\npublic:\n";
@@ -1496,69 +1522,53 @@ void EmitClangAttrClass(RecordKeeper &Re
     if (!ElideSpelling)
       OS << CreateSemanticSpellings(Spellings, SemanticToSyntacticMap);
 
-    OS << "  static " << R.getName() << "Attr *CreateImplicit(";
-    OS << "ASTContext &Ctx";
-    if (!ElideSpelling)
-      OS << ", Spelling S";
-    for (auto const &ai : Args) {
-      OS << ", ";
-      ai->writeCtorParameters(OS);
-    }
-    OS << ", SourceRange Loc = SourceRange()";
-    OS << ") {\n";
-    OS << "    " << R.getName() << "Attr *A = new (Ctx) " << R.getName();
-    OS << "Attr(Loc, Ctx, ";
-    for (auto const &ai : Args) {
-      ai->writeImplicitCtorArgs(OS);
-      OS << ", ";
-    }
-    OS << (ElideSpelling ? "0" : "S") << ");\n";
-    OS << "    A->setImplicit(true);\n";
-    OS << "    return A;\n  }\n\n";
-
-    OS << "  " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n";
-    
-    bool HasOpt = false;
-    for (auto const &ai : Args) {
-      OS << "              , ";
-      ai->writeCtorParameters(OS);
-      OS << "\n";
-      if (ai->isOptional())
-        HasOpt = true;
-    }
-
-    OS << "              , ";
-    OS << "unsigned SI\n";
-
-    OS << "             )\n";
-    OS << "    : " << SuperName << "(attr::" << R.getName() << ", R, SI, "
-       << R.getValueAsBit("LateParsed") << ", "
-       << R.getValueAsBit("DuplicatesAllowedWhileMerging") << ")\n";
-
-    for (auto const &ai : Args) {
-      OS << "              , ";
-      ai->writeCtorInitializers(OS);
-      OS << "\n";
-    }
-
-    OS << "  {\n";
-  
-    for (auto const &ai : Args) {
-      ai->writeCtorBody(OS);
-      OS << "\n";
-    }
-    OS << "  }\n\n";
+    // Emit CreateImplicit factory methods.
+    auto emitCreateImplicit = [&](bool emitFake) {
+      OS << "  static " << R.getName() << "Attr *CreateImplicit(";
+      OS << "ASTContext &Ctx";
+      if (!ElideSpelling)
+        OS << ", Spelling S";
+      for (auto const &ai : Args) {
+        if (ai->isFake() && !emitFake) continue;
+        OS << ", ";
+        ai->writeCtorParameters(OS);
+      }
+      OS << ", SourceRange Loc = SourceRange()";
+      OS << ") {\n";
+      OS << "    " << R.getName() << "Attr *A = new (Ctx) " << R.getName();
+      OS << "Attr(Loc, Ctx, ";
+      for (auto const &ai : Args) {
+        if (ai->isFake() && !emitFake) continue;
+        ai->writeImplicitCtorArgs(OS);
+        OS << ", ";
+      }
+      OS << (ElideSpelling ? "0" : "S") << ");\n";
+      OS << "    A->setImplicit(true);\n";
+      OS << "    return A;\n  }\n\n";
+    };
+
+    // Emit a CreateImplicit that takes all the arguments.
+    emitCreateImplicit(true);
+
+    // Emit a CreateImplicit that takes all the non-fake arguments.
+    if (HasFakeArg) {
+      emitCreateImplicit(false);
+    }
+
+    // Emit constructors.
+    auto emitCtor = [&](bool emitOpt, bool emitFake) {
+      auto shouldEmitArg = [=](const std::unique_ptr<Argument> &arg) {
+        if (arg->isFake()) return emitFake;
+        if (arg->isOptional()) return emitOpt;
+        return true;
+      };
 
-    // If there are optional arguments, write out a constructor that elides the
-    // optional arguments as well.
-    if (HasOpt) {
       OS << "  " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n";
       for (auto const &ai : Args) {
-        if (!ai->isOptional()) {
-          OS << "              , ";
-          ai->writeCtorParameters(OS);
-          OS << "\n";
-        }
+        if (!shouldEmitArg(ai)) continue;
+        OS << "              , ";
+        ai->writeCtorParameters(OS);
+        OS << "\n";
       }
 
       OS << "              , ";
@@ -1571,19 +1581,37 @@ void EmitClangAttrClass(RecordKeeper &Re
 
       for (auto const &ai : Args) {
         OS << "              , ";
-        ai->writeCtorDefaultInitializers(OS);
+        if (!shouldEmitArg(ai)) {
+          ai->writeCtorDefaultInitializers(OS);
+        } else {
+          ai->writeCtorInitializers(OS);
+        }
         OS << "\n";
       }
 
       OS << "  {\n";
   
       for (auto const &ai : Args) {
-        if (!ai->isOptional()) {
-          ai->writeCtorBody(OS);
-          OS << "\n";
-        }
+        if (!shouldEmitArg(ai)) continue;
+        ai->writeCtorBody(OS);
+        OS << "\n";
       }
       OS << "  }\n\n";
+
+    };
+
+    // Emit a constructor that includes all the arguments.
+    // This is necessary for cloning.
+    emitCtor(true, true);
+
+    // Emit a constructor that takes all the non-fake arguments.
+    if (HasFakeArg) {
+      emitCtor(true, false);
+    }
+ 
+    // Emit a constructor that takes all the non-fake, non-optional arguments.
+    if (HasOptArg) {
+      emitCtor(false, false);
     }
 
     OS << "  " << R.getName() << "Attr *clone(ASTContext &C) const;\n";
@@ -1605,6 +1633,9 @@ void EmitClangAttrClass(RecordKeeper &Re
       ai->writeAccessors(OS);
       OS << "\n\n";
 
+      // Don't write conversion routines for fake arguments.
+      if (ai->isFake()) continue;
+
       if (ai->isEnumArg())
         static_cast<const EnumArgument *>(ai.get())->writeConversion(OS);
       else if (ai->isVariadicEnumArg())




More information about the cfe-commits mailing list