capture sourcelocation info for type specifiers. This improves diagnostics

for things like 'short _Complex'.

llvm-svn: 39227
This commit is contained in:
Chris Lattner 2006-11-28 05:30:29 +00:00
parent 60809f5aaf
commit b20e89449f
6 changed files with 63 additions and 50 deletions

View File

@ -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));

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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));

View File

@ -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);
};