From b20e89449f8f69a9118ae50d79197d21108134ca Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Tue, 28 Nov 2006 05:30:29 +0000 Subject: [PATCH] capture sourcelocation info for type specifiers. This improves diagnostics for things like 'short _Complex'. llvm-svn: 39227 --- clang/AST/SemaDecl.cpp | 2 +- clang/Parse/DeclSpec.cpp | 35 +++++++++++------- clang/Parse/ParseDecl.cpp | 55 +++++++++++++--------------- clang/Parse/Parser.cpp | 2 +- clang/Sema/SemaDecl.cpp | 2 +- clang/include/clang/Parse/DeclSpec.h | 17 ++++++--- 6 files changed, 63 insertions(+), 50 deletions(-) diff --git a/clang/AST/SemaDecl.cpp b/clang/AST/SemaDecl.cpp index ff4bb9b0678b..3273177011fa 100644 --- a/clang/AST/SemaDecl.cpp +++ b/clang/AST/SemaDecl.cpp @@ -137,7 +137,7 @@ Decl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, // Set a Declarator for the implicit definition: int foo(); const char *Dummy; DeclSpec DS; - bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Dummy); + bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy); assert(!Error && "Error setting up implicit decl!"); Declarator D(DS, Declarator::BlockContext); D.AddTypeInfo(DeclaratorTypeInfo::getFunction(false, false, true, Loc)); diff --git a/clang/Parse/DeclSpec.cpp b/clang/Parse/DeclSpec.cpp index 6fcfe0c9e9a3..d415774bd72f 100644 --- a/clang/Parse/DeclSpec.cpp +++ b/clang/Parse/DeclSpec.cpp @@ -141,34 +141,42 @@ bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc, /// These methods set the specified attribute of the DeclSpec, but return true /// and ignore the request if invalid (e.g. "extern" then "auto" is /// specified). -bool DeclSpec::SetTypeSpecWidth(TSW W, const char *&PrevSpec) { +bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc, + const char *&PrevSpec) { if (TypeSpecWidth != TSW_unspecified && // Allow turning long -> long long. (W != TSW_longlong || TypeSpecWidth != TSW_long)) return BadSpecifier(TypeSpecWidth, PrevSpec); TypeSpecWidth = W; + TSWLoc = Loc; return false; } -bool DeclSpec::SetTypeSpecComplex(TSC C, const char *&PrevSpec) { +bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc, + const char *&PrevSpec) { if (TypeSpecComplex != TSC_unspecified) return BadSpecifier(TypeSpecComplex, PrevSpec); TypeSpecComplex = C; + TSCLoc = Loc; return false; } -bool DeclSpec::SetTypeSpecSign(TSS S, const char *&PrevSpec) { +bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc, + const char *&PrevSpec) { if (TypeSpecSign != TSS_unspecified) return BadSpecifier(TypeSpecSign, PrevSpec); TypeSpecSign = S; + TSSLoc = Loc; return false; } -bool DeclSpec::SetTypeSpecType(TST T, const char *&PrevSpec, void *TypeRep) { +bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, + const char *&PrevSpec, void *TypeRep) { if (TypeSpecType != TST_unspecified) return BadSpecifier(TypeSpecType, PrevSpec); TypeSpecType = T; TypenameRep = TypeRep; + TSTLoc = Loc; return false; } @@ -200,8 +208,7 @@ bool DeclSpec::SetFunctionSpecInline(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(SourceLocation Loc, Diagnostic &D, - const LangOptions &Lang) { +void DeclSpec::Finish(Diagnostic &D, const LangOptions &Lang) { // Check the type specifier components first. // signed/unsigned are only valid with int/char. @@ -209,7 +216,8 @@ void DeclSpec::Finish(SourceLocation Loc, Diagnostic &D, if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. else if (TypeSpecType != TST_int && TypeSpecType != TST_char) { - D.Report(Loc, diag::err_invalid_sign_spec,getSpecifierName(TypeSpecType)); + D.Report(TSSLoc, diag::err_invalid_sign_spec, + getSpecifierName(TypeSpecType)); // signed double -> double. TypeSpecSign = TSS_unspecified; } @@ -223,8 +231,9 @@ void DeclSpec::Finish(SourceLocation Loc, Diagnostic &D, if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // short -> short int, long long -> long long int. else if (TypeSpecType != TST_int) { - D.Report(Loc, TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec : - diag::err_invalid_longlong_spec, + D.Report(TSWLoc, + TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec + : diag::err_invalid_longlong_spec, getSpecifierName(TypeSpecType)); TypeSpecType = TST_int; } @@ -233,7 +242,7 @@ void DeclSpec::Finish(SourceLocation Loc, Diagnostic &D, if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // long -> long int. else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { - D.Report(Loc, diag::err_invalid_long_spec, + D.Report(TSWLoc, diag::err_invalid_long_spec, getSpecifierName(TypeSpecType)); TypeSpecType = TST_int; } @@ -244,13 +253,13 @@ void DeclSpec::Finish(SourceLocation Loc, Diagnostic &D, // disallow their use. Need information about the backend. if (TypeSpecComplex != TSC_unspecified) { if (TypeSpecType == TST_unspecified) { - D.Report(Loc, diag::ext_plain_complex); + D.Report(TSCLoc, diag::ext_plain_complex); TypeSpecType = TST_double; // _Complex -> _Complex double. } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { // Note that this intentionally doesn't include _Complex _Bool. - D.Report(Loc, diag::ext_integer_complex); + D.Report(TSTLoc, diag::ext_integer_complex); } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) { - D.Report(Loc, diag::err_invalid_complex_spec, + D.Report(TSCLoc, diag::err_invalid_complex_spec, getSpecifierName(TypeSpecType)); TypeSpecComplex = TSC_unspecified; } diff --git a/clang/Parse/ParseDecl.cpp b/clang/Parse/ParseDecl.cpp index 8c9d40bff7b7..561cf38411a9 100644 --- a/clang/Parse/ParseDecl.cpp +++ b/clang/Parse/ParseDecl.cpp @@ -247,8 +247,6 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS) { /// [C99] 'inline' /// void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { - // FIXME: Remove this. - SourceLocation StartLoc = Tok.getLocation(); while (1) { int isInvalid = false; const char *PrevSpec = 0; @@ -264,7 +262,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { // It has to be available as a typedef too! if (void *TypeRep = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) { - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, PrevSpec, + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec, TypeRep); } break; @@ -273,8 +271,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { default: // If this is not a declaration specifier token, we're done reading decl // specifiers. First verify that DeclSpec's are consistent. - // FIXME: Remove StartLoc. - DS.Finish(StartLoc, Diags, getLang()); + DS.Finish(Diags, getLang()); return; // GNU attributes support. @@ -308,52 +305,52 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { // type-specifiers case tok::kw_short: - isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, PrevSpec); + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec); break; case tok::kw_long: if (DS.getTypeSpecWidth() != DeclSpec::TSW_long) - isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, PrevSpec); + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec); else - isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, PrevSpec); + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec); break; case tok::kw_signed: - isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, PrevSpec); + isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec); break; case tok::kw_unsigned: - isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, PrevSpec); + isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec); break; case tok::kw__Complex: - isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, PrevSpec); + isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec); break; case tok::kw__Imaginary: - isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, PrevSpec); + isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec); break; case tok::kw_void: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec); break; case tok::kw_char: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec); break; case tok::kw_int: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec); break; case tok::kw_float: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec); break; case tok::kw_double: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec); break; case tok::kw__Bool: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec); break; case tok::kw__Decimal32: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec); break; case tok::kw__Decimal64: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec); break; case tok::kw__Decimal128: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec); break; case tok::kw_struct: @@ -433,7 +430,7 @@ void Parser::ParseStructUnionSpecifier(DeclSpec &DS) { assert((Tok.getKind() == tok::kw_struct || Tok.getKind() == tok::kw_union) && "Not a struct/union specifier"); bool isUnion = Tok.getKind() == tok::kw_union; - SourceLocation Start = ConsumeToken(); + SourceLocation StartLoc = ConsumeToken(); // If attributes exist after tag, parse them. if (Tok.getKind() == tok::kw___attribute) @@ -530,8 +527,8 @@ void Parser::ParseStructUnionSpecifier(DeclSpec &DS) { const char *PrevSpec = 0; if (DS.SetTypeSpecType(isUnion ? DeclSpec::TST_union : DeclSpec::TST_struct, - PrevSpec)) - Diag(Start, diag::err_invalid_decl_spec_combination, PrevSpec); + StartLoc, PrevSpec)) + Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec); } @@ -554,7 +551,7 @@ void Parser::ParseStructUnionSpecifier(DeclSpec &DS) { /// void Parser::ParseEnumSpecifier(DeclSpec &DS) { assert(Tok.getKind() == tok::kw_enum && "Not an enum specifier"); - SourceLocation Start = ConsumeToken(); + SourceLocation StartLoc = ConsumeToken(); if (Tok.getKind() == tok::kw___attribute) ParseAttributes(); @@ -604,8 +601,8 @@ void Parser::ParseEnumSpecifier(DeclSpec &DS) { const char *PrevSpec = 0; - if (DS.SetTypeSpecType(DeclSpec::TST_enum, PrevSpec)) - Diag(Start, diag::err_invalid_decl_spec_combination, PrevSpec); + if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec)) + Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec); } @@ -714,7 +711,6 @@ bool Parser::isDeclarationSpecifier() const { /// [GNU] type-qualifier-list attributes /// void Parser::ParseTypeQualifierListOpt(DeclSpec &DS) { - SourceLocation StartLoc = Tok.getLocation(); while (1) { int isInvalid = false; const char *PrevSpec = 0; @@ -724,7 +720,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS) { default: // If this is not a type-qualifier token, we're done reading type // qualifiers. First verify that DeclSpec's are consistent. - DS.Finish(StartLoc, Diags, getLang()); + DS.Finish(Diags, getLang()); return; case tok::kw_const: isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, @@ -746,6 +742,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS) { // If the specifier combination wasn't legal, issue a diagnostic. if (isInvalid) { + // FIXME: emit a matching caret at the previous illegal spec combination. assert(PrevSpec && "Method did not return previous specifier!"); if (isInvalid == 1) // Error. Diag(Tok, diag::err_invalid_decl_spec_combination, PrevSpec); diff --git a/clang/Parse/Parser.cpp b/clang/Parse/Parser.cpp index 47df33159411..1e5c7537b5a8 100644 --- a/clang/Parse/Parser.cpp +++ b/clang/Parse/Parser.cpp @@ -240,7 +240,7 @@ void Parser::Initialize() { Dummy); // TODO: add a 'TST_builtin' type? - Error |= DS.SetTypeSpecType(DeclSpec::TST_int, Dummy); + Error |= DS.SetTypeSpecType(DeclSpec::TST_int, SourceLocation(), Dummy); assert(!Error && "Error setting up __builtin_va_list!"); Declarator D(DS, Declarator::FileContext); diff --git a/clang/Sema/SemaDecl.cpp b/clang/Sema/SemaDecl.cpp index ff4bb9b0678b..3273177011fa 100644 --- a/clang/Sema/SemaDecl.cpp +++ b/clang/Sema/SemaDecl.cpp @@ -137,7 +137,7 @@ Decl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, // Set a Declarator for the implicit definition: int foo(); const char *Dummy; DeclSpec DS; - bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Dummy); + bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy); assert(!Error && "Error setting up implicit decl!"); Declarator D(DS, Declarator::BlockContext); D.AddTypeInfo(DeclaratorTypeInfo::getFunction(false, false, true, Loc)); diff --git a/clang/include/clang/Parse/DeclSpec.h b/clang/include/clang/Parse/DeclSpec.h index ddbb6b31915b..b4598ed07deb 100644 --- a/clang/include/clang/Parse/DeclSpec.h +++ b/clang/include/clang/Parse/DeclSpec.h @@ -121,6 +121,7 @@ private: // SourceLocation info. These are null if the item wasn't specified or if // the setting was synthesized. SourceLocation StorageClassSpecLoc, SCS_threadLoc; + SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc; SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc; SourceLocation FS_inlineLoc; public: @@ -159,6 +160,11 @@ public: TST getTypeSpecType() const { return TypeSpecType; } void *getTypenameRep() const { return TypenameRep; } + SourceLocation getTypeSpecWidthLoc() const { return TSWLoc; } + SourceLocation getTypeSpecComplexLoc() const { return TSCLoc; } + SourceLocation getTypeSpecSignLoc() const { return TSSLoc; } + SourceLocation getTypeSpecTypeLoc() const { return TSTLoc; } + // type-qualifiers /// getTypeQualifiers - Return a set of TQs. @@ -195,10 +201,11 @@ public: /// specified). The name of the previous specifier is returned in prevspec. bool SetStorageClassSpec(SCS S, SourceLocation Loc, const char *&PrevSpec); bool SetStorageClassSpecThread(SourceLocation Loc, const char *&PrevSpec); - bool SetTypeSpecWidth(TSW W, const char *&PrevSpec); - bool SetTypeSpecComplex(TSC C, const char *&PrevSpec); - bool SetTypeSpecSign(TSS S, const char *&PrevSpec); - bool SetTypeSpecType(TST T, const char *&PrevSpec, void *TypenameRep = 0); + bool SetTypeSpecWidth(TSW W, SourceLocation Loc, const char *&PrevSpec); + bool SetTypeSpecComplex(TSC C, SourceLocation Loc, const char *&PrevSpec); + bool SetTypeSpecSign(TSS S, SourceLocation Loc, const char *&PrevSpec); + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + void *TypenameRep = 0); bool SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, const LangOptions &Lang); @@ -208,7 +215,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(SourceLocation Loc, Diagnostic &D,const LangOptions &Lang); + void Finish(Diagnostic &D,const LangOptions &Lang); };