diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-04-24 05:37:28 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-04-24 05:37:28 +0000 |
commit | 312eadb832cab4497a069409954500d8192b8f0d (patch) | |
tree | f919e5f5b0f8f0e2092ee948b86f92a7171697a2 /lib/Parse/ParseDecl.cpp | |
parent | 1b6005285e234bc30698917b2d3abb2f1f98bc77 (diff) |
Implement a new identifier-classification scheme where Sema
performs name lookup for an identifier and resolves it to a
type/expression/template/etc. in the same step. This scheme is
intended to improve both performance (by reducing the number of
redundant name lookups for a given identifier token) and error
recovery (by giving Sema a chance to correct type names before the
parser has decided that the identifier isn't a type name). For
example, this allows us to properly typo-correct type names at the
beginning of a statement:
t.c:6:3: error: use of undeclared identifier 'integer'; did you mean
'Integer'?
integer *i = 0;
^~~~~~~
Integer
t.c:1:13: note: 'Integer' declared here
typedef int Integer;
^
Previously, we wouldn't give a Fix-It because the typo correction
occurred after the parser had checked whether "integer" was a type
name (via Sema::getTypeName(), which isn't allowed to typo-correct)
and therefore decided to parse "integer * i = 0" as an expression. By
typo-correcting earlier, we typo-correct to the type name Integer and
parse this as a declaration.
Moreover, in this context, we can also typo-correct identifiers to
keywords, e.g.,
t.c:7:3: error: use of undeclared identifier 'vid'; did you mean
'void'?
vid *p = i;
^~~
void
and recover appropriately.
Note that this is very much a work-in-progress. The new
Sema::ClassifyName is only used for expression-or-declaration
disambiguation in C at the statement level. The next steps will be to
make this work for the same disambiguation in C++ (where
functional-style casts make some trouble), then push it
further into the parser to eliminate more redundant name lookups.
Fixes <rdar://problem/7963833> for C and starts us down the path of
<rdar://problem/8172000>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130082 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParseDecl.cpp')
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 40 |
1 files changed, 33 insertions, 7 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 0b06d6a4fd..c09a93a84f 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -724,23 +724,46 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts, // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); DS.takeAttributesFrom(attrs); + return ParseSimpleDeclaration(DS, Stmts, Context, DeclEnd, RequireSemi, FRI); +} + +/// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl] +/// declaration-specifiers init-declarator-list[opt] ';' +///[C90/C++]init-declarator-list ';' [TODO] +/// [OMP] threadprivate-directive [TODO] +/// +/// for-range-declaration: [C++0x 6.5p1: stmt.ranged] +/// attribute-specifier-seq[opt] type-specifier-seq declarator +/// +/// If RequireSemi is false, this does not check for a ';' at the end of the +/// declaration. If it is true, it checks for and eats it. +/// +/// If FRI is non-null, we might be parsing a for-range-declaration instead +/// of a simple-declaration. If we find that we are, we also parse the +/// for-range-initializer, and place it here. +Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(ParsingDeclSpec &DS, + StmtVector &Stmts, + unsigned Context, + SourceLocation &DeclEnd, + bool RequireSemi, + ForRangeInit *FRI) { ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, getDeclSpecContextFromDeclaratorContext(Context)); StmtResult R = Actions.ActOnVlaStmt(DS); if (R.isUsable()) Stmts.push_back(R.release()); - + // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { if (RequireSemi) ConsumeToken(); Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, - DS); + DS); DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } - - return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI); + + return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI); } /// ParseDeclGroup - Having concluded that this is either a function @@ -1254,9 +1277,12 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, - DeclSpecContext DSContext) { - DS.SetRangeStart(Tok.getLocation()); - DS.SetRangeEnd(Tok.getLocation()); + DeclSpecContext DSContext) { + if (DS.getSourceRange().isInvalid()) { + DS.SetRangeStart(Tok.getLocation()); + DS.SetRangeEnd(Tok.getLocation()); + } + while (1) { bool isInvalid = false; const char *PrevSpec = 0; |