Index: test/SemaCXX/attr-print.cpp =================================================================== --- test/SemaCXX/attr-print.cpp +++ test/SemaCXX/attr-print.cpp @@ -34,3 +34,27 @@ // CHECK: void callableWhen() __attribute__((callable_when("unconsumed", "consumed"))); void callableWhen() __attribute__((callable_when("unconsumed", "consumed"))); }; + +// CHECK: class __single_inheritance SingleInheritance; +class __single_inheritance SingleInheritance; + +// CHECK: void sentinel(int a, ...) __attribute__((sentinel)); +void sentinel(int a, ...) __attribute__((sentinel)); + +// CHECK: void sentinel_1n(int a, ...) __attribute__((sentinel(1))); +void sentinel_1n(int a, ...) __attribute__((sentinel(1))); + +// CHECK: void sentinel_1d2n(int a, ...) __attribute__((sentinel(0, 1))); +void sentinel_1d2n(int a, ...) __attribute__((sentinel(0, 1))); + +// CHECK: void sentinel_1n2n(int a, ...) __attribute__((sentinel(1, 1))); +void sentinel_1n2n(int a, ...) __attribute__((sentinel(1, 1))); + +// It would be better if we didn't lose arguments in the following cases, but +// at least the default values have the same semantics. + +// CHECK: void sentinel_1d(int a, ...) __attribute__((sentinel)); +void sentinel_1d(int a, ...) __attribute__((sentinel(0))); + +// CHECK: void sentinel_1d2d(int a, ...) __attribute__((sentinel)); +void sentinel_1d2d(int a, ...) __attribute__((sentinel(0, 0))); Index: utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -374,6 +374,11 @@ OS << Default; OS << ";"; } + + std::string getIsOmitted() const override { + return "Default" + getUpperName().str() + " == get" + + getUpperName().str() + "()"; + } }; class StringArgument : public Argument { @@ -1432,6 +1437,7 @@ unsigned NonFakeArgs = 0; unsigned TrailingOptArgs = 0; bool FoundNonOptArg = false; + std::string Indent = " "; for (const auto &arg : llvm::reverse(Args)) { if (arg->isFake()) continue; @@ -1446,9 +1452,14 @@ } if (!TrailingOptArgs++) OS << "\";\n" - << " unsigned TrailingOmittedArgs = 0;\n"; - OS << " if (" << arg->getIsOmitted() << ")\n" - << " ++TrailingOmittedArgs;\n"; + << Indent << "unsigned TrailingOmittedArgs = 0;\n"; + OS << Indent << "if (" << arg->getIsOmitted() << ") {\n"; + Indent += " "; + OS << Indent << "++TrailingOmittedArgs;\n"; + } + for (unsigned i = 0; i < TrailingOptArgs; ++i) { + Indent.resize(Indent.size() - 2); + OS << Indent << "}\n"; } if (TrailingOptArgs) OS << " OS << \""; @@ -1463,26 +1474,21 @@ 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") + if (ArgIndex >= NonFakeArgs - TrailingOptArgs) { OS << "\";\n" - << " if (!(" << IsOmitted << ")) {\n" - << " OS << \""; + << " if (" << ArgIndex << " < " << NonFakeArgs + << " - TrailingOmittedArgs) {\n"; + if (ArgIndex) + OS << " OS << \", \";\n"; + OS << " OS << \""; + } else if (ArgIndex) + OS << ", "; arg->writeValue(OS); - if (arg->isOptional() && IsOmitted != "false") + if (ArgIndex >= NonFakeArgs - TrailingOptArgs) { OS << "\";\n" << " }\n" << " OS << \""; + } ++ArgIndex; } if (TrailingOptArgs < NonFakeArgs)