diff --git a/clang/test/AST/ast-print-attr.c b/clang/test/AST/ast-print-attr.c --- a/clang/test/AST/ast-print-attr.c +++ b/clang/test/AST/ast-print-attr.c @@ -26,3 +26,9 @@ MyErrFirst, MyErrSecond, }; + +// CHECK: int *fun_returns() __attribute__((ownership_returns(fun_returns))); +int *fun_returns() __attribute__((ownership_returns(fun_returns))); + +// CHECK: void fun_holds(int *a) __attribute__((ownership_holds(fun_holds, 1))); +void fun_holds(int *a) __attribute__((ownership_holds(fun_holds, 1))); diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -773,10 +773,8 @@ void writeValue(raw_ostream &OS) const override { OS << "\";\n"; - OS << " bool isFirst = true;\n" - << " for (const auto &Val : " << RangeName << "()) {\n" - << " if (isFirst) isFirst = false;\n" - << " else OS << \", \";\n"; + OS << " for (const auto &Val : " << RangeName << "()) {\n" + << " DelimitAttributeArgument(OS, IsFirstArgument);\n"; writeValueImpl(OS); OS << " }\n"; OS << " OS << \""; @@ -1428,10 +1426,12 @@ return; } - OS << " switch (getAttributeSpellingListIndex()) {\n" - " default:\n" - " llvm_unreachable(\"Unknown attribute spelling!\");\n" - " break;\n"; + OS << " bool IsFirstArgument = true; (void)IsFirstArgument;\n" + << " unsigned TrailingOmittedArgs = 0; (void)TrailingOmittedArgs;\n" + << " switch (getAttributeSpellingListIndex()) {\n" + << " default:\n" + << " llvm_unreachable(\"Unknown attribute spelling!\");\n" + << " break;\n"; for (unsigned I = 0; I < Spellings.size(); ++ I) { llvm::SmallString<16> Prefix; @@ -1476,12 +1476,10 @@ Spelling += Name; - OS << - " case " << I << " : {\n" - " OS << \"" << Prefix << Spelling; + OS << " case " << I << " : {\n" + << " OS << \"" << Prefix << Spelling << "\";\n"; if (Variety == "Pragma") { - OS << "\";\n"; OS << " printPrettyPragma(OS, Policy);\n"; OS << " OS << \"\\n\";"; OS << " break;\n"; @@ -1490,19 +1488,18 @@ } if (Spelling == "availability") { - OS << "("; + OS << " OS << \"("; writeAvailabilityValue(OS); - OS << ")"; + OS << ")\";\n"; } else if (Spelling == "deprecated" || Spelling == "gnu::deprecated") { - OS << "("; + OS << " OS << \"("; writeDeprecatedAttrValue(OS, Variety); - OS << ")"; + OS << ")\";\n"; } else { // To avoid printing parentheses around an empty argument list or // printing spurious commas at the end of an argument list, we need to // determine where the last provided non-fake argument is. unsigned NonFakeArgs = 0; - unsigned TrailingOptArgs = 0; bool FoundNonOptArg = false; for (const auto &arg : llvm::reverse(Args)) { if (arg->isFake()) @@ -1516,61 +1513,33 @@ FoundNonOptArg = true; continue; } - if (!TrailingOptArgs++) - OS << "\";\n" - << " unsigned TrailingOmittedArgs = 0;\n"; OS << " if (" << arg->getIsOmitted() << ")\n" << " ++TrailingOmittedArgs;\n"; } - if (TrailingOptArgs) - OS << " OS << \""; - if (TrailingOptArgs < NonFakeArgs) - OS << "("; - else if (TrailingOptArgs) - OS << "\";\n" - << " if (TrailingOmittedArgs < " << NonFakeArgs << ")\n" - << " OS << \"(\";\n" - << " OS << \""; unsigned ArgIndex = 0; for (const auto &arg : Args) { if (arg->isFake()) continue; - if (ArgIndex) { - if (ArgIndex >= NonFakeArgs - TrailingOptArgs) - OS << "\";\n" - << " if (" << ArgIndex << " < " << NonFakeArgs - << " - TrailingOmittedArgs)\n" - << " OS << \", \";\n" - << " OS << \""; - else - OS << ", "; - } std::string IsOmitted = arg->getIsOmitted(); if (arg->isOptional() && IsOmitted != "false") - OS << "\";\n" - << " if (!(" << IsOmitted << ")) {\n" - << " OS << \""; + OS << " if (!(" << IsOmitted << ")) {\n"; + // Variadic arguments print their own leading comma. + if (!arg->isVariadic()) + OS << " DelimitAttributeArgument(OS, IsFirstArgument);\n"; + OS << " OS << \""; arg->writeValue(OS); + OS << "\";\n"; if (arg->isOptional() && IsOmitted != "false") - OS << "\";\n" - << " }\n" - << " OS << \""; + OS << " }\n"; ++ArgIndex; } - if (TrailingOptArgs < NonFakeArgs) - OS << ")"; - else if (TrailingOptArgs) - OS << "\";\n" - << " if (TrailingOmittedArgs < " << NonFakeArgs << ")\n" - << " OS << \")\";\n" - << " OS << \""; + if (ArgIndex != 0) + OS << " if (!IsFirstArgument)\n" + << " OS << \")\";\n"; } - - OS << Suffix + "\";\n"; - - OS << - " break;\n" - " }\n"; + OS << " OS << \"" << Suffix << "\";\n" + << " break;\n" + << " }\n"; } // End of the switch statement. @@ -2279,6 +2248,18 @@ std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); ParsedAttrMap AttrMap = getParsedAttrList(Records); + // Helper to print the starting character of an attribute argument. If there + // hasn't been an argument yet, it prints an opening parenthese; otherwise it + // prints a comma. + OS << "static inline void DelimitAttributeArgument(" + << "raw_ostream& OS, bool& IsFirst) {\n" + << " if (IsFirst) {\n" + << " IsFirst = false;\n" + << " OS << \"(\";\n" + << " } else\n" + << " OS << \", \";\n" + << "}\n"; + for (const auto *Attr : Attrs) { const Record &R = *Attr;