diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -1213,8 +1213,35 @@ } PP.LexUnexpandedToken(Tok); - SourceLocation StringLoc = Tok.getLocation(); + SourceLocation StartLineLoc, EndLineLoc; + if (Tok.is(tok::identifier)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + if (II->isStr("line")) { + // The pragma only applies to the next line. + auto &SM = PP.getSourceManager(); + FullSourceLoc FullLoc(DiagLoc, SM); + bool Invalid; + unsigned Line = FullLoc.getLineNumber(&Invalid); + assert(!Invalid && "Invalid line number"); + + // The start location will be the start of the next line. + StartLineLoc = SM.translateLineCol(FullLoc.getFileID(), Line + 1, + /*Col=*/1); + + // The end location will be the end of the next line. + // Pass UINT_MAX for the column since translateLineCol() will stop at + // the first newline character, or end of the buffer, if the column + // exceeds the line length. + EndLineLoc = SM.translateLineCol(FullLoc.getFileID(), Line + 1, + /*Col=*/UINT_MAX); + + // Continue to get the warning as a string. + PP.LexUnexpandedToken(Tok); + } + } + + SourceLocation StringLoc = Tok.getLocation(); std::string WarningName; if (!PP.FinishLexStringLiteral(Tok, WarningName, "pragma diagnostic", /*AllowMacroExpansion=*/false)) @@ -1235,14 +1262,26 @@ : diag::Flavor::Remark; StringRef Group = StringRef(WarningName).substr(2); bool unknownDiag = false; + + if (StartLineLoc.isValid()) + PP.getDiagnostics().pushMappings(StartLineLoc); + if (Group == "everything") { // Special handling for pragma clang diagnostic ... "-Weverything". // There is no formal group named "everything", so there has to be a // special case for it. PP.getDiagnostics().setSeverityForAll(Flavor, SV, DiagLoc); - } else + } else if (StartLineLoc.isValid()) { + unknownDiag = PP.getDiagnostics().setSeverityForGroup(Flavor, Group, SV, + StartLineLoc); + } else { unknownDiag = PP.getDiagnostics().setSeverityForGroup(Flavor, Group, SV, DiagLoc); + } + + if (EndLineLoc.isValid()) + PP.getDiagnostics().popMappings(EndLineLoc); + if (unknownDiag) PP.Diag(StringLoc, diag::warn_pragma_diagnostic_unknown_warning) << WarningName; diff --git a/clang/test/Preprocessor/pragma_diagnostic_line.c b/clang/test/Preprocessor/pragma_diagnostic_line.c new file mode 100644 --- /dev/null +++ b/clang/test/Preprocessor/pragma_diagnostic_line.c @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wall -Wsign-conversion %s + +void func(int *x); + +#define NODEREF __attribute__((noderef)) + +void test(NODEREF int *x) { + func(x); // expected-warning{{casting to dereferenceable pointer removes 'noderef' attribute}} + +#pragma clang diagnostic ignored line "-Wnoderef" + func(x); // No warning. + + // Warning diagnosed again. + func(x); // expected-warning{{casting to dereferenceable pointer removes 'noderef' attribute}} + + // Only -Wnoderef is ignored. + int *y; // expected-note{{initialize the variable 'y' to silence this warning}} +#pragma clang diagnostic ignored line "-Wnoderef" + func(x); + func(y); // expected-warning{{variable 'y' is uninitialized when used here}} + + // The 1st ignored line doesn't really do anything since there aren't any + // statements on the next line. +#pragma clang diagnostic ignored line "-Wnoderef" +#pragma clang diagnostic ignored line "-Wnoderef" + func(x); + +#pragma clang diagnostic ignored line "-Wnoderef" + // This warns since it's not immediately after the ignored line. + func(x); // expected-warning{{casting to dereferenceable pointer removes 'noderef' attribute}} + +#pragma clang diagnostic warning line "-Wnoderef" + func(x); // expected-warning{{casting to dereferenceable pointer removes 'noderef' attribute}} +#pragma clang diagnostic error line "-Wnoderef" + func(x); // expected-error{{casting to dereferenceable pointer removes 'noderef' attribute}} + + int s = 0; + unsigned int u = 0; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnoderef" + s = u; // expected-warning{{implicit conversion changes signedness: 'unsigned int' to 'int'}} + func(x); // ok +#pragma clang diagnostic ignored line "-Wsign-conversion" + s = u; // ok + s = u; // expected-warning{{implicit conversion changes signedness: 'unsigned int' to 'int'}} +#pragma clang diagnostic pop + func(x); // expected-warning{{casting to dereferenceable pointer removes 'noderef' attribute}} + s = u; // expected-warning{{implicit conversion changes signedness: 'unsigned int' to 'int'}} +} + +#pragma clang diagnostic ignored line "-Wnoderef" +void end_of_file(NODEREF int *x) { func(x); }