From: Douglas Gregor Date: Wed, 1 Apr 2009 22:41:11 +0000 (+0000) Subject: Add code modification hints to various parsing-related diagnostics. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9b3064b55f3c858923734e8b1c9831777fc22554;p=clang Add code modification hints to various parsing-related diagnostics. Plus, reword a extension warnings to avoid talking about "ISO C" when the extension might also be available in C++ or C++0x. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68257 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index a040d3532a..c2e90e8da4 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -17,15 +17,15 @@ def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">; def ext_empty_source_file : Extension<"ISO C forbids an empty source file">; def ext_top_level_semi : Extension< - "ISO C does not allow an extra ';' outside of a function">; + "extra ';' outside of a function">; def ext_extra_struct_semi : Extension< - "ISO C does not allow an extra ';' inside a struct or union">; + "extra ';' inside a struct or union">; def ext_duplicate_declspec : Extension<"duplicate '%0' declaration specifier">; -def ext_plain_complex : Extension< - "ISO C does not support plain '_Complex' meaning '_Complex double'">; +def ext_plain_complex : ExtWarn< + "plain '_Complex' requires a type specifier; assuming '_Complex double'">; def ext_integer_complex : Extension< - "ISO C does not support complex integer types">; + "complex integer types are an extension">; def ext_thread_before : Extension<"'__thread' before 'static'">; def ext_empty_struct_union_enum : Extension<"use of empty %0 extension">; @@ -43,8 +43,8 @@ def ext_c99_variable_decl_in_for_loop : Extension< "variable declaration in for loop is a C99-specific feature">; def ext_c99_compound_literal : Extension< "compound literals are a C99-specific feature">; -def ext_c99_enumerator_list_comma : Extension< - "commas at the end of enumerator lists are a C99-specific feature">; +def ext_enumerator_list_comma : Extension< + "commas at the end of enumerator lists are a %select{C99|C++0x}0-specific feature">; def ext_gnu_indirect_goto : Extension< "use of GNU indirect-goto extension">; diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 248d78a023..5d78192e1d 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -324,7 +324,7 @@ public: /// Finish - This does final analysis of the declspec, issuing diagnostics for /// things like "_Imaginary" (lacking an FP type). After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. - void Finish(Diagnostic &D, SourceManager& SrcMgr, const LangOptions &Lang); + void Finish(Diagnostic &D, Preprocessor &PP); /// isMissingDeclaratorOk - This checks if this DeclSpec can stand alone, /// without a Declarator. Only tag declspecs can stand alone. diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index de9f36dd9c..40675de989 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -13,6 +13,7 @@ #include "clang/Parse/DeclSpec.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Basic/LangOptions.h" #include "llvm/ADT/STLExtras.h" #include @@ -283,9 +284,9 @@ bool DeclSpec::SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec /// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or /// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. -void DeclSpec::Finish(Diagnostic &D, SourceManager& SrcMgr, - const LangOptions &Lang) { +void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { // Check the type specifier components first. + SourceManager &SrcMgr = PP.getSourceManager(); // signed/unsigned are only valid with int/char/wchar_t. if (TypeSpecSign != TSS_unspecified) { @@ -330,7 +331,10 @@ void DeclSpec::Finish(Diagnostic &D, SourceManager& SrcMgr, // disallow their use. Need information about the backend. if (TypeSpecComplex != TSC_unspecified) { if (TypeSpecType == TST_unspecified) { - Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex); + Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex) + << CodeModificationHint::CreateInsertion( + PP.getLocForEndOfToken(getTypeSpecComplexLoc()), + " double"); TypeSpecType = TST_double; // _Complex -> _Complex double. } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { // Note that this intentionally doesn't include _Complex _Bool. diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index e233a22162..104ca0336b 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -496,7 +496,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DoneWithDeclSpec: // If this is not a declaration specifier token, we're done reading decl // specifiers. First verify that DeclSpec's are consistent. - DS.Finish(Diags, PP.getSourceManager(), getLang()); + DS.Finish(Diags, PP); return; case tok::coloncolon: // ::foo::bar @@ -1169,7 +1169,8 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { - Diag(Tok, diag::ext_extra_struct_semi); + Diag(Tok, diag::ext_extra_struct_semi) + << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); ConsumeToken(); continue; } @@ -1372,8 +1373,11 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) { break; SourceLocation CommaLoc = ConsumeToken(); - if (Tok.isNot(tok::identifier) && !getLang().C99) - Diag(CommaLoc, diag::ext_c99_enumerator_list_comma); + if (Tok.isNot(tok::identifier) && + !(getLang().C99 || getLang().CPlusPlus0x)) + Diag(CommaLoc, diag::ext_enumerator_list_comma) + << getLang().CPlusPlus + << CodeModificationHint::CreateRemoval((SourceRange(CommaLoc))); } // Eat the }. @@ -1625,7 +1629,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) { DoneWithTypeQuals: // If this is not a type-qualifier token, we're done reading type // qualifiers. First verify that DeclSpec's are consistent. - DS.Finish(Diags, PP.getSourceManager(), getLang()); + DS.Finish(Diags, PP); return; } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 5865771f60..f00edddffe 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -608,7 +608,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { // GNU typeof support. case tok::kw_typeof: ParseTypeofSpecifier(DS); - DS.Finish(Diags, PP.getSourceManager(), getLang()); + DS.Finish(Diags, PP); return; } if (Tok.is(tok::annot_typename)) @@ -616,7 +616,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { else DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); - DS.Finish(Diags, PP.getSourceManager(), getLang()); + DS.Finish(Diags, PP); } /// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++ diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 8903da29a0..5b38f60abe 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -372,7 +372,8 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { DeclPtrTy SingleDecl; switch (Tok.getKind()) { case tok::semi: - Diag(Tok, diag::ext_top_level_semi); + Diag(Tok, diag::ext_top_level_semi) + << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); ConsumeToken(); // TODO: Invoke action for top-level semicolon. return DeclGroupPtrTy(); diff --git a/test/Sema/fixit-c90.c b/test/Sema/fixit-c90.c new file mode 100644 index 0000000000..125e5f8f3a --- /dev/null +++ b/test/Sema/fixit-c90.c @@ -0,0 +1,11 @@ +/* RUN: clang -fsyntax-only -std=c90 -pedantic %s + */ +/* This is a test of the various code modification hints that are + provided as part of warning or extension diagnostics. Eventually, + we would like to actually try to perform the suggested + modifications and compile the result to test that no warnings + remain. */ + +enum e0 { + e1, +}; diff --git a/test/Sema/fixit.c b/test/Sema/fixit.c new file mode 100644 index 0000000000..e2443cc52f --- /dev/null +++ b/test/Sema/fixit.c @@ -0,0 +1,18 @@ +// RUN: clang -fsyntax-only -pedantic %s + +/* This is a test of the various code modification hints that are + provided as part of warning or extension diagnostics. Eventually, + we would like to actually try to perform the suggested + modifications and compile the result to test that no warnings + remain. */ + +void f0(void) { }; + +struct s { + int x, y;; +}; + +_Complex cd; + +struct s s0 = { y: 5 }; +int array0[5] = { [3] 3 }; diff --git a/test/SemaCXX/fixit.cpp b/test/SemaCXX/fixit.cpp new file mode 100644 index 0000000000..db0cd8ce18 --- /dev/null +++ b/test/SemaCXX/fixit.cpp @@ -0,0 +1,14 @@ +// RUN: clang-cc -fsyntax-only -pedantic -verify %s + +/* This is a test of the various code modification hints that are + provided as part of warning or extension diagnostics. Eventually, + we would like to actually try to perform the suggested + modifications and compile the result to test that no warnings + remain. */ + +struct C1 { }; +struct C2 : virtual public virtual C1 { }; // expected-error{{duplicate}} + +template struct CT { }; + +CT<10 >> 2> ct; // expected-warning{{require parentheses}}