[llvm-branch-commits] [cfe-branch] r195165 - Merging r195163:
Bill Wendling
isanbard at gmail.com
Tue Nov 19 14:56:43 PST 2013
Author: void
Date: Tue Nov 19 16:56:43 2013
New Revision: 195165
URL: http://llvm.org/viewvc/llvm-project?rev=195165&view=rev
Log:
Merging r195163:
------------------------------------------------------------------------
r195163 | rsmith | 2013-11-19 14:47:36 -0800 (Tue, 19 Nov 2013) | 5 lines
PR9547: If we're parsing a simple-declaration that contains a tag definition,
and we see an ill-formed declarator that would probably be well-formed if the
tag definition were just missing a semicolon, use that as the diagnostic
instead of producing some other mysterious error.
------------------------------------------------------------------------
Modified:
cfe/branches/release_34/ (props changed)
cfe/branches/release_34/include/clang/Parse/Parser.h
cfe/branches/release_34/include/clang/Sema/DeclSpec.h
cfe/branches/release_34/lib/Parse/ParseDecl.cpp
cfe/branches/release_34/lib/Parse/ParseDeclCXX.cpp
cfe/branches/release_34/lib/Parse/Parser.cpp
cfe/branches/release_34/lib/Sema/DeclSpec.cpp
cfe/branches/release_34/lib/Sema/SemaType.cpp
cfe/branches/release_34/test/Parser/cxx-decl.cpp
cfe/branches/release_34/test/Parser/recovery.cpp
Propchange: cfe/branches/release_34/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Nov 19 16:56:43 2013
@@ -1,4 +1,4 @@
/cfe/branches/type-system-rewrite:134693-134817
-/cfe/trunk:195126,195128,195135-195136
+/cfe/trunk:195126,195128,195135-195136,195163
/cfe/trunk/test:170344
/cfe/trunk/test/SemaTemplate:126920
Modified: cfe/branches/release_34/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/include/clang/Parse/Parser.h?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/include/clang/Parse/Parser.h (original)
+++ cfe/branches/release_34/include/clang/Parse/Parser.h Tue Nov 19 16:56:43 2013
@@ -1647,6 +1647,9 @@ private:
AccessSpecifier AS = AS_none,
DeclSpecContext DSC = DSC_normal,
LateParsedAttrList *LateAttrs = 0);
+ bool DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
+ DeclSpecContext DSContext,
+ LateParsedAttrList *LateAttrs = 0);
void ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none,
DeclSpecContext DSC = DSC_normal);
Modified: cfe/branches/release_34/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/include/clang/Sema/DeclSpec.h?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/include/clang/Sema/DeclSpec.h (original)
+++ cfe/branches/release_34/include/clang/Sema/DeclSpec.h Tue Nov 19 16:56:43 2013
@@ -461,6 +461,12 @@ public:
ThreadStorageClassSpecLoc = SourceLocation();
}
+ void ClearTypeSpecType() {
+ TypeSpecType = DeclSpec::TST_unspecified;
+ TypeSpecOwned = false;
+ TSTLoc = SourceLocation();
+ }
+
// type-specifier
TSW getTypeSpecWidth() const { return (TSW)TypeSpecWidth; }
TSC getTypeSpecComplex() const { return (TSC)TypeSpecComplex; }
@@ -507,6 +513,8 @@ public:
return TypeSpecType == TST_auto || TypeSpecType == TST_decltype_auto;
}
+ bool hasTagDefinition() const;
+
/// \brief Turn a type-specifier-type into a string like "_Bool" or "union".
static const char *getSpecifierName(DeclSpec::TST T);
static const char *getSpecifierName(DeclSpec::TQ Q);
Modified: cfe/branches/release_34/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Parse/ParseDecl.cpp?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/lib/Parse/ParseDecl.cpp (original)
+++ cfe/branches/release_34/lib/Parse/ParseDecl.cpp Tue Nov 19 16:56:43 2013
@@ -1401,8 +1401,14 @@ Parser::ParseSimpleDeclaration(StmtVecto
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this);
- ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
- getDeclSpecContextFromDeclaratorContext(Context));
+ DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(Context);
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, DSContext);
+
+ // If we had a free-standing type definition with a missing semicolon, we
+ // may get this far before the problem becomes obvious.
+ if (DS.hasTagDefinition() &&
+ DiagnoseMissingSemiAfterTagDefinition(DS, AS_none, DSContext))
+ return DeclGroupPtrTy();
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
@@ -2318,6 +2324,101 @@ void Parser::ParseAlignmentSpecifier(Par
AttributeList::AS_Keyword, EllipsisLoc);
}
+/// Determine whether we're looking at something that might be a declarator
+/// in a simple-declaration. If it can't possibly be a declarator, maybe
+/// diagnose a missing semicolon after a prior tag definition in the decl
+/// specifier.
+///
+/// \return \c true if an error occurred and this can't be any kind of
+/// declaration.
+bool
+Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
+ DeclSpecContext DSContext,
+ LateParsedAttrList *LateAttrs) {
+ assert(DS.hasTagDefinition() && "shouldn't call this");
+
+ bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level);
+ bool HasMissingSemi = false;
+
+ if (getLangOpts().CPlusPlus &&
+ (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
+ Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id)) &&
+ TryAnnotateCXXScopeToken(EnteringContext)) {
+ SkipMalformedDecl();
+ return true;
+ }
+
+ // Determine whether the following tokens could possibly be a
+ // declarator.
+ if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) {
+ const Token &Next = NextToken();
+ // These tokens cannot come after the declarator-id in a
+ // simple-declaration, and are likely to come after a type-specifier.
+ HasMissingSemi = Next.is(tok::star) || Next.is(tok::amp) ||
+ Next.is(tok::ampamp) || Next.is(tok::identifier) ||
+ Next.is(tok::annot_cxxscope) ||
+ Next.is(tok::coloncolon);
+ } else if (Tok.is(tok::annot_cxxscope) &&
+ NextToken().is(tok::identifier) &&
+ DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
+ // We almost certainly have a missing semicolon. Look up the name and
+ // check; if it names a type, we're missing a semicolon.
+ CXXScopeSpec SS;
+ Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
+ Tok.getAnnotationRange(), SS);
+ const Token &Next = NextToken();
+ IdentifierInfo *Name = Next.getIdentifierInfo();
+ Sema::NameClassification Classification =
+ Actions.ClassifyName(getCurScope(), SS, Name, Next.getLocation(),
+ NextToken(), /*IsAddressOfOperand*/false);
+ switch (Classification.getKind()) {
+ case Sema::NC_Error:
+ SkipMalformedDecl();
+ return true;
+
+ case Sema::NC_Keyword:
+ case Sema::NC_NestedNameSpecifier:
+ llvm_unreachable("typo correction and nested name specifiers not "
+ "possible here");
+
+ case Sema::NC_Type:
+ case Sema::NC_TypeTemplate:
+ // Not a previously-declared non-type entity.
+ HasMissingSemi = true;
+ break;
+
+ case Sema::NC_Unknown:
+ case Sema::NC_Expression:
+ case Sema::NC_VarTemplate:
+ case Sema::NC_FunctionTemplate:
+ // Might be a redeclaration of a prior entity.
+ HasMissingSemi = false;
+ break;
+ }
+ } else if (Tok.is(tok::kw_typename) || Tok.is(tok::annot_typename)) {
+ HasMissingSemi = true;
+ }
+
+ if (!HasMissingSemi)
+ return false;
+
+ Diag(PP.getLocForEndOfToken(DS.getRepAsDecl()->getLocEnd()),
+ diag::err_expected_semi_after_tagdecl)
+ << DeclSpec::getSpecifierName(DS.getTypeSpecType());
+
+ // Try to recover from the typo, by dropping the tag definition and parsing
+ // the problematic tokens as a type.
+ //
+ // FIXME: Split the DeclSpec into pieces for the standalone
+ // declaration and pieces for the following declaration, instead
+ // of assuming that all the other pieces attach to new declaration,
+ // and call ParsedFreeStandingDeclSpec as appropriate.
+ DS.ClearTypeSpecType();
+ ParsedTemplateInfo NotATemplate;
+ ParseDeclarationSpecifiers(DS, NotATemplate, AS, DSContext, LateAttrs);
+ return false;
+}
+
/// ParseDeclarationSpecifiers
/// declaration-specifiers: [C99 6.7]
/// storage-class-specifier declaration-specifiers[opt]
@@ -2586,6 +2687,11 @@ void Parser::ParseDeclarationSpecifiers(
}
case tok::annot_typename: {
+ // If we've previously seen a tag definition, we were almost surely
+ // missing a semicolon after it.
+ if (DS.hasTypeSpecifier() && DS.hasTagDefinition())
+ goto DoneWithDeclSpec;
+
if (Tok.getAnnotationValue()) {
ParsedType T = getTypeAnnotation(Tok);
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
Modified: cfe/branches/release_34/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Parse/ParseDeclCXX.cpp?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/branches/release_34/lib/Parse/ParseDeclCXX.cpp Tue Nov 19 16:56:43 2013
@@ -2077,6 +2077,14 @@ void Parser::ParseCXXClassMemberDeclarat
ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,
&CommonLateParsedAttrs);
+ // If we had a free-standing type definition with a missing semicolon, we
+ // may get this far before the problem becomes obvious.
+ if (DS.hasTagDefinition() &&
+ TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate &&
+ DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_class,
+ &CommonLateParsedAttrs))
+ return;
+
MultiTemplateParamsArg TemplateParams(
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0,
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0);
Modified: cfe/branches/release_34/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Parse/Parser.cpp?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/lib/Parse/Parser.cpp (original)
+++ cfe/branches/release_34/lib/Parse/Parser.cpp Tue Nov 19 16:56:43 2013
@@ -875,6 +875,12 @@ Parser::ParseDeclOrFunctionDefInternal(P
// Parse the common declaration-specifiers piece.
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_top_level);
+ // If we had a free-standing type definition with a missing semicolon, we
+ // may get this far before the problem becomes obvious.
+ if (DS.hasTagDefinition() &&
+ DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_top_level))
+ return DeclGroupPtrTy();
+
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
if (Tok.is(tok::semi)) {
Modified: cfe/branches/release_34/lib/Sema/DeclSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Sema/DeclSpec.cpp?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/lib/Sema/DeclSpec.cpp (original)
+++ cfe/branches/release_34/lib/Sema/DeclSpec.cpp Tue Nov 19 16:56:43 2013
@@ -333,6 +333,12 @@ bool Declarator::isStaticMember() {
getName().OperatorFunctionId.Operator);
}
+bool DeclSpec::hasTagDefinition() const {
+ if (!TypeSpecOwned)
+ return false;
+ return cast<TagDecl>(getRepAsDecl())->isCompleteDefinition();
+}
+
/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
/// declaration specifier includes.
///
Modified: cfe/branches/release_34/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Sema/SemaType.cpp?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/lib/Sema/SemaType.cpp (original)
+++ cfe/branches/release_34/lib/Sema/SemaType.cpp Tue Nov 19 16:56:43 2013
@@ -2990,13 +2990,12 @@ static TypeSourceInfo *GetFullTypeForDec
}
}
- if (LangOpts.CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) {
+ if (LangOpts.CPlusPlus && D.getDeclSpec().hasTagDefinition()) {
// C++ [dcl.fct]p6:
// Types shall not be defined in return or parameter types.
TagDecl *Tag = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
- if (Tag->isCompleteDefinition())
- S.Diag(Tag->getLocation(), diag::err_type_defined_in_result_type)
- << Context.getTypeDeclType(Tag);
+ S.Diag(Tag->getLocation(), diag::err_type_defined_in_result_type)
+ << Context.getTypeDeclType(Tag);
}
// Exception specs are not allowed in typedefs. Complain, but add it
Modified: cfe/branches/release_34/test/Parser/cxx-decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/test/Parser/cxx-decl.cpp?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/test/Parser/cxx-decl.cpp (original)
+++ cfe/branches/release_34/test/Parser/cxx-decl.cpp Tue Nov 19 16:56:43 2013
@@ -108,9 +108,9 @@ template<class T>
class Class1;
class Class2 {
-} // no ;
+} // expected-error {{expected ';' after class}}
-typedef Class1<Class2> Type1; // expected-error {{cannot combine with previous 'class' declaration specifier}}
+typedef Class1<Class2> Type1;
// rdar : // 8307865
struct CodeCompleteConsumer {
Modified: cfe/branches/release_34/test/Parser/recovery.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/test/Parser/recovery.cpp?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/test/Parser/recovery.cpp (original)
+++ cfe/branches/release_34/test/Parser/recovery.cpp Tue Nov 19 16:56:43 2013
@@ -66,3 +66,56 @@ struct Redefined { // expected-note {{pr
struct Redefined { // expected-error {{redefinition}}
Redefined() {}
};
+
+struct MissingSemi5;
+namespace N {
+ typedef int afterMissingSemi4;
+ extern MissingSemi5 afterMissingSemi5;
+}
+
+struct MissingSemi1 {} // expected-error {{expected ';' after struct}}
+static int afterMissingSemi1();
+
+class MissingSemi2 {} // expected-error {{expected ';' after class}}
+MissingSemi1 *afterMissingSemi2;
+
+enum MissingSemi3 {} // expected-error {{expected ';' after enum}}
+::MissingSemi1 afterMissingSemi3;
+
+extern N::afterMissingSemi4 afterMissingSemi4b;
+union MissingSemi4 { MissingSemi4(int); } // expected-error {{expected ';' after union}}
+N::afterMissingSemi4 (afterMissingSemi4b);
+
+int afterMissingSemi5b;
+struct MissingSemi5 { MissingSemi5(int); } // ok, no missing ';' here
+N::afterMissingSemi5 (afterMissingSemi5b);
+
+template<typename T> struct MissingSemiT {
+} // expected-error {{expected ';' after struct}}
+MissingSemiT<int> msi;
+
+struct MissingSemiInStruct {
+ struct Inner1 {} // expected-error {{expected ';' after struct}}
+ static MissingSemi5 ms1;
+
+ struct Inner2 {} // ok, no missing ';' here
+ static MissingSemi1;
+
+ struct Inner3 {} // expected-error {{expected ';' after struct}}
+ static MissingSemi5 *p;
+};
+
+void MissingSemiInFunction() {
+ struct Inner1 {} // expected-error {{expected ';' after struct}}
+ if (true) {}
+
+ // FIXME: It would be nice to at least warn on this.
+ struct Inner2 { Inner2(int); } // ok, no missing ';' here
+ k = l;
+
+ struct Inner3 {} // expected-error {{expected ';' after struct}}
+ Inner1 i1;
+
+ struct Inner4 {} // ok, no missing ';' here
+ Inner5;
+}
More information about the llvm-branch-commits
mailing list