From: Chris Lattner Date: Wed, 25 Jul 2007 00:24:17 +0000 (+0000) Subject: Fix a couple of bugs, add some new cool stuff. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e80a59cc41d42a970466cb020b6f44c5b8831d70;p=clang Fix a couple of bugs, add some new cool stuff. 1. Fix a todo in Parser::ParseTag, to recover better. On code like that in test/Sema/decl-invalid.c it causes us to return a single error instead of multiple. 2. Fix an error in Sema::ParseDeclarator, where it would crash if the declarator didn't have an identifier. Instead, diagnose the problem. 3. Start adding infrastructure to track the range of locations covered by a declspec or declarator. This is mostly implemented for declspec, but could be improved, it is missing for declarator. Thanks to Neil for pointing out this crash. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@40482 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Parse/DeclSpec.cpp b/Parse/DeclSpec.cpp index 117ff12e59..d3ddf47a83 100644 --- a/Parse/DeclSpec.cpp +++ b/Parse/DeclSpec.cpp @@ -277,7 +277,6 @@ void DeclSpec::Finish(Diagnostic &D, const LangOptions &Lang) { } // Okay, now we can infer the real type. - // TODO: infer real type. // TODO: return "auto function" and other bad things based on the real type. diff --git a/Parse/ParseDecl.cpp b/Parse/ParseDecl.cpp index c40e749659..b05fd7898d 100644 --- a/Parse/ParseDecl.cpp +++ b/Parse/ParseDecl.cpp @@ -296,7 +296,6 @@ ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) { void Parser::ParseSpecifierQualifierList(DeclSpec &DS) { /// specifier-qualifier-list is a subset of declaration-specifiers. Just /// parse declaration-specifiers and complain about extra stuff. - SourceLocation Loc = Tok.getLocation(); ParseDeclarationSpecifiers(DS); // Validate declspec for type-name. @@ -367,6 +366,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS) { /// [C99] 'inline' /// void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { + DS.Range.setBegin(Tok.getLocation()); while (1) { int isInvalid = false; const char *PrevSpec = 0; @@ -509,6 +509,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { else // extwarn. Diag(Tok, diag::ext_duplicate_declspec, PrevSpec); } + DS.Range.setEnd(Tok.getLocation()); ConsumeToken(); } } @@ -527,7 +528,9 @@ bool Parser::ParseTag(DeclTy *&Decl, unsigned TagType, SourceLocation StartLoc){ if (Tok.getKind() != tok::identifier && Tok.getKind() != tok::l_brace) { Diag(Tok, diag::err_expected_ident_lbrace); - // TODO: better error recovery here. + + // Skip the rest of this declarator, up until the comma or semicolon. + SkipUntil(tok::comma, true); return true; } diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index c546df27cc..3053d2e2a8 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -278,6 +278,14 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *init, Expr *Init = static_cast(init); IdentifierInfo *II = D.getIdentifier(); + // All of these full declarators require an identifier. If it doesn't have + // one, the ParsedFreeStandingDeclSpec action should be used. + if (II == 0) { + Diag(D.getDeclSpec().getSourceRange().Begin(), diag::err_declarator_need_ident, + D.getDeclSpec().getSourceRange(), D.getSourceRange()); + return 0; + } + // See if this is a redefinition of a variable in the same scope. Decl *PrevDecl = LookupScopedDecl(II, Decl::IDNS_Ordinary, D.getIdentifierLoc(), S); diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 4069bda645..64de3aa16e 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -427,6 +427,8 @@ DIAG(err_invalid_storage_class_in_func_decl, ERROR, "invalid storage class specifier in function declarator") DIAG(err_invalid_reference_qualifier_application, ERROR, "'%0' qualifier may not be applied to a reference") +DIAG(err_declarator_need_ident, ERROR, + "declarator requires an identifier") // Attributes DIAG(err_attribute_wrong_number_arguments, ERROR, diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h index 6ba17b0530..2ebed47b72 100644 --- a/include/clang/Basic/SourceLocation.h +++ b/include/clang/Basic/SourceLocation.h @@ -161,6 +161,9 @@ public: SourceLocation Begin() const { return B; } SourceLocation End() const { return E; } + void setBegin(SourceLocation b) { B = b; } + void setEnd(SourceLocation e) { E = e; } + bool isValid() const { return B.isValid() && E.isValid(); } }; diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 95be993831..7c5fb1a00b 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -28,6 +28,9 @@ namespace clang { /// and function-specifiers. class DeclSpec { public: + SourceRange Range; + const SourceRange &getSourceRange() const { return Range; } + // storage-class-specifier enum SCS { SCS_unspecified, @@ -414,8 +417,8 @@ struct DeclaratorChunk { /// Abstract declarators are used when parsing types, and don't have an /// identifier. Normal declarators do have ID's. /// -/// This is NOT intended to be a small value object: this should be a transient -/// object that lives on the stack. +/// Instances of this class should be a transient object that lives on the +/// stack, not objects that are allocated in large quantities on the heap. class Declarator { const DeclSpec &DS; IdentifierInfo *Identifier; @@ -459,6 +462,9 @@ public: TheContext getContext() const { return Context; } + // getSourceRange - FIXME: This should be implemented. + const SourceRange getSourceRange() const { return SourceRange(); } + /// clear - Reset the contents of this Declarator. void clear() { Identifier = 0; diff --git a/test/Sema/decl-invalid.c b/test/Sema/decl-invalid.c new file mode 100644 index 0000000000..dda6601dc9 --- /dev/null +++ b/test/Sema/decl-invalid.c @@ -0,0 +1,3 @@ +// RUN: clang %s -parse-ast-check + +typedef union __mbstate_t; // expected-error: {{expected identifier or}}