capture sourcelocation info for type specifiers. This improves diagnostics
for things like 'short _Complex'. llvm-svn: 39227
This commit is contained in:
parent
60809f5aaf
commit
b20e89449f
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue