record accurate sourceloc info for storage class specs, so we can report
things like: t.c:4:10: error: invalid storage class specifier in function declarator int foo2(auto int Aaslfkasdflkj, register B); ^ instead of: t.c:4:19: error: invalid storage class specifier in function declarator int foo2(auto int Aaslfkasdflkj, register B); ^ llvm-svn: 39224
This commit is contained in:
parent
353f5740b1
commit
4d8f873b5b
|
@ -25,7 +25,7 @@ unsigned DeclSpec::getParsedSpecifiers() const {
|
|||
SCS_thread_specified)
|
||||
Res |= PQ_StorageClassSpecifier;
|
||||
|
||||
if (TypeQualifiers != TQ_unspecified)
|
||||
if (TypeQualifiers != TQ_unspecified)
|
||||
Res |= PQ_TypeQualifier;
|
||||
|
||||
if (hasTypeSpecifier())
|
||||
|
@ -117,19 +117,23 @@ static bool BadSpecifier(DeclSpec::TQ T, const char *&PrevSpec) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DeclSpec::SetStorageClassSpec(SCS S, const char *&PrevSpec) {
|
||||
bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc,
|
||||
const char *&PrevSpec) {
|
||||
if (StorageClassSpec != SCS_unspecified)
|
||||
return BadSpecifier(StorageClassSpec, PrevSpec);
|
||||
StorageClassSpec = S;
|
||||
StorageClassSpecLoc = Loc;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeclSpec::SetStorageClassSpecThread(const char *&PrevSpec) {
|
||||
bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc,
|
||||
const char *&PrevSpec) {
|
||||
if (SCS_thread_specified) {
|
||||
PrevSpec = "__thread";
|
||||
return true;
|
||||
}
|
||||
SCS_thread_specified = true;
|
||||
SCS_threadLoc = Loc;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -250,7 +254,7 @@ void DeclSpec::Finish(SourceLocation Loc, Diagnostic &D,
|
|||
StorageClassSpec = SCS_extern; // '__thread int' -> 'extern __thread int'
|
||||
} else if (StorageClassSpec != SCS_extern &&
|
||||
StorageClassSpec != SCS_static) {
|
||||
D.Report(Loc, diag::err_invalid_thread_spec,
|
||||
D.Report(getStorageClassSpecLoc(), diag::err_invalid_thread_spec,
|
||||
getSpecifierName(StorageClassSpec));
|
||||
SCS_thread_specified = false;
|
||||
}
|
||||
|
|
|
@ -244,10 +244,13 @@ 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;
|
||||
SourceLocation Loc = Tok.getLocation();
|
||||
|
||||
switch (Tok.getKind()) {
|
||||
// typedef-name
|
||||
case tok::identifier:
|
||||
|
@ -267,6 +270,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());
|
||||
return;
|
||||
|
||||
|
@ -277,26 +281,26 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) {
|
|||
|
||||
// storage-class-specifier
|
||||
case tok::kw_typedef:
|
||||
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, PrevSpec);
|
||||
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec);
|
||||
break;
|
||||
case tok::kw_extern:
|
||||
if (DS.isThreadSpecified())
|
||||
Diag(Tok, diag::ext_thread_before, "extern");
|
||||
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, PrevSpec);
|
||||
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec);
|
||||
break;
|
||||
case tok::kw_static:
|
||||
if (DS.isThreadSpecified())
|
||||
Diag(Tok, diag::ext_thread_before, "static");
|
||||
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, PrevSpec);
|
||||
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec);
|
||||
break;
|
||||
case tok::kw_auto:
|
||||
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, PrevSpec);
|
||||
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec);
|
||||
break;
|
||||
case tok::kw_register:
|
||||
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, PrevSpec);
|
||||
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec);
|
||||
break;
|
||||
case tok::kw___thread:
|
||||
isInvalid = DS.SetStorageClassSpecThread(PrevSpec)*2;
|
||||
isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec)*2;
|
||||
break;
|
||||
|
||||
// type-specifiers
|
||||
|
@ -989,12 +993,16 @@ void Parser::ParseParenDeclarator(Declarator &D) {
|
|||
case DeclSpec::SCS_auto:
|
||||
// NOTE: we could trivially allow 'int foo(auto int X)' if we wanted.
|
||||
default:
|
||||
// FIXME: Get better loc info from declspecs!
|
||||
Diag(DeclaratorInfo.getIdentifierLoc(),
|
||||
Diag(DS.getStorageClassSpecLoc(),
|
||||
diag::err_invalid_storage_class_in_func_decl);
|
||||
DS.ClearStorageClassSpecs();
|
||||
break;
|
||||
}
|
||||
if (DS.isThreadSpecified()) {
|
||||
Diag(DS.getThreadSpecLoc(),
|
||||
diag::err_invalid_storage_class_in_func_decl);
|
||||
DS.ClearStorageClassSpecs();
|
||||
}
|
||||
|
||||
// Inform the actions module about the parameter declarator, so it gets
|
||||
// added to the current scope.
|
||||
|
|
|
@ -236,7 +236,8 @@ void Parser::Initialize() {
|
|||
|
||||
//__builtin_va_list
|
||||
DeclSpec DS;
|
||||
bool Error = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Dummy);
|
||||
bool Error = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, SourceLocation(),
|
||||
Dummy);
|
||||
|
||||
// TODO: add a 'TST_builtin' type?
|
||||
Error |= DS.SetTypeSpecType(DeclSpec::TST_int, Dummy);
|
||||
|
|
|
@ -117,6 +117,11 @@ private:
|
|||
|
||||
// attributes.
|
||||
// FIXME: implement declspec attributes.
|
||||
|
||||
// SourceLocation info. These are null if the item wasn't specified or if
|
||||
// the setting was synthesized.
|
||||
SourceLocation StorageClassSpecLoc, SCS_threadLoc;
|
||||
|
||||
public:
|
||||
|
||||
DeclSpec()
|
||||
|
@ -135,9 +140,15 @@ public:
|
|||
SCS getStorageClassSpec() const { return StorageClassSpec; }
|
||||
bool isThreadSpecified() const { return SCS_thread_specified; }
|
||||
|
||||
SourceLocation getStorageClassSpecLoc() const { return StorageClassSpecLoc; }
|
||||
SourceLocation getThreadSpecLoc() const { return SCS_threadLoc; }
|
||||
|
||||
|
||||
void ClearStorageClassSpecs() {
|
||||
StorageClassSpec = DeclSpec::SCS_unspecified;
|
||||
SCS_thread_specified = false;
|
||||
StorageClassSpecLoc = SourceLocation();
|
||||
SCS_threadLoc = SourceLocation();
|
||||
}
|
||||
|
||||
// type-specifier
|
||||
|
@ -175,8 +186,8 @@ public:
|
|||
/// 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). The name of the previous specifier is returned in prevspec.
|
||||
bool SetStorageClassSpec(SCS S, const char *&PrevSpec);
|
||||
bool SetStorageClassSpecThread(const char *&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);
|
||||
|
|
Loading…
Reference in New Issue