Awesome! Thanks Richard! -- Sean Silva
On Mon, Oct 14, 2013 at 8:00 PM, Richard Smith <[email protected]>wrote: > Author: rsmith > Date: Mon Oct 14 19:00:26 2013 > New Revision: 192644 > > URL: http://llvm.org/viewvc/llvm-project?rev=192644&view=rev > Log: > PR17567: Improve diagnostic for a mistyped constructor name. If we see > something > that looks like a function declaration, except that it's missing a return > type, > try typo-correcting it to the relevant constructor name. > > In passing, fix a bug where the missing-type-specifier recovery codepath > would > drop a preceding scope specifier on the floor, leading to follow-on > diagnostics > and incorrect recovery for the auto-in-c++98 hack. > > Modified: > cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td > cfe/trunk/include/clang/Sema/Sema.h > cfe/trunk/lib/Parse/ParseDecl.cpp > cfe/trunk/lib/Sema/SemaDeclCXX.cpp > cfe/trunk/test/CXX/drs/dr1xx.cpp > cfe/trunk/test/Parser/cxx-decl.cpp > cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp > cfe/trunk/test/SemaCXX/nested-name-spec.cpp > cfe/trunk/test/SemaTemplate/alias-nested-nontag.cpp > > Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=192644&r1=192643&r2=192644&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Mon Oct 14 > 19:00:26 2013 > @@ -482,6 +482,8 @@ def err_expected_rbrace_or_comma : Error > def err_expected_rsquare_or_comma : Error<"expected ']' or ','">; > def err_using_namespace_in_class : Error< > "'using namespace' is not allowed in classes">; > +def err_constructor_bad_name : Error< > + "missing return type for function %0; did you mean the constructor name > %1?">; > def err_destructor_tilde_identifier : Error< > "expected a class name after '~' to name a destructor">; > def err_destructor_template_id : Error< > > Modified: cfe/trunk/include/clang/Sema/Sema.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=192644&r1=192643&r2=192644&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Sema/Sema.h (original) > +++ cfe/trunk/include/clang/Sema/Sema.h Mon Oct 14 19:00:26 2013 > @@ -4606,6 +4606,7 @@ public: > // > bool isCurrentClassName(const IdentifierInfo &II, Scope *S, > const CXXScopeSpec *SS = 0); > + bool isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec > *SS); > > bool ActOnAccessSpecifier(AccessSpecifier Access, > SourceLocation ASLoc, > > Modified: cfe/trunk/lib/Parse/ParseDecl.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=192644&r1=192643&r2=192644&view=diff > > ============================================================================== > --- cfe/trunk/lib/Parse/ParseDecl.cpp (original) > +++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Oct 14 19:00:26 2013 > @@ -2095,6 +2095,8 @@ bool Parser::ParseImplicitInt(DeclSpec & > DS.getStorageClassSpec() == DeclSpec::SCS_auto) { > // Don't require a type specifier if we have the 'auto' storage class > // specifier in C++98 -- we'll promote it to a type specifier. > + if (SS) > + AnnotateScopeToken(*SS, /*IsNewAnnotation*/false); > return false; > } > > @@ -2156,16 +2158,6 @@ bool Parser::ParseImplicitInt(DeclSpec & > // Look ahead to the next token to try to figure out what this > declaration > // was supposed to be. > switch (NextToken().getKind()) { > - case tok::comma: > - case tok::equal: > - case tok::kw_asm: > - case tok::l_brace: > - case tok::l_square: > - case tok::semi: > - // This looks like a variable declaration. The type is probably > missing. > - // We're done parsing decl-specifiers. > - return false; > - > case tok::l_paren: { > // static x(4); // 'x' is not a type > // x(int n); // 'x' is not a type > @@ -2178,12 +2170,37 @@ bool Parser::ParseImplicitInt(DeclSpec & > ConsumeToken(); > TPResult TPR = TryParseDeclarator(/*mayBeAbstract*/false); > PA.Revert(); > - if (TPR == TPResult::False()) > - return false; > - // The identifier is followed by a parenthesized declarator. > - // It's supposed to be a type. > - break; > + > + if (TPR != TPResult::False()) { > + // The identifier is followed by a parenthesized declarator. > + // It's supposed to be a type. > + break; > + } > + > + // If we're in a context where we could be declaring a constructor, > + // check whether this is a constructor declaration with a bogus > name. > + if (DSC == DSC_class || (DSC == DSC_top_level && SS)) { > + IdentifierInfo *II = Tok.getIdentifierInfo(); > + if (Actions.isCurrentClassNameTypo(II, SS)) { > + Diag(Loc, diag::err_constructor_bad_name) > + << Tok.getIdentifierInfo() << II > + << FixItHint::CreateReplacement(Tok.getLocation(), > II->getName()); > + Tok.setIdentifierInfo(II); > + } > + } > + // Fall through. > } > + case tok::comma: > + case tok::equal: > + case tok::kw_asm: > + case tok::l_brace: > + case tok::l_square: > + case tok::semi: > + // This looks like a variable or function declaration. The type is > + // probably missing. We're done parsing decl-specifiers. > + if (SS) > + AnnotateScopeToken(*SS, /*IsNewAnnotation*/false); > + return false; > > default: > // This is probably supposed to be a type. This includes cases like: > > Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=192644&r1=192643&r2=192644&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) > +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Oct 14 19:00:26 2013 > @@ -1227,6 +1227,32 @@ bool Sema::isCurrentClassName(const Iden > return false; > } > > +/// \brief Determine whether the identifier II is a typo for the name of > +/// the class type currently being defined. If so, update it to the > identifier > +/// that should have been used. > +bool Sema::isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec > *SS) { > + assert(getLangOpts().CPlusPlus && "No class names in C!"); > + > + if (!getLangOpts().SpellChecking) > + return false; > + > + CXXRecordDecl *CurDecl; > + if (SS && SS->isSet() && !SS->isInvalid()) { > + DeclContext *DC = computeDeclContext(*SS, true); > + CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC); > + } else > + CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext); > + > + if (CurDecl && CurDecl->getIdentifier() && II != > CurDecl->getIdentifier() && > + 3 * II->getName().edit_distance(CurDecl->getIdentifier()->getName()) > + < II->getLength()) { > + II = CurDecl->getIdentifier(); > + return true; > + } > + > + return false; > +} > + > /// \brief Determine whether the given class is a base class of the given > /// class, including looking at dependent bases. > static bool findCircularInheritance(const CXXRecordDecl *Class, > > Modified: cfe/trunk/test/CXX/drs/dr1xx.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr1xx.cpp?rev=192644&r1=192643&r2=192644&view=diff > > ============================================================================== > --- cfe/trunk/test/CXX/drs/dr1xx.cpp (original) > +++ cfe/trunk/test/CXX/drs/dr1xx.cpp Mon Oct 14 19:00:26 2013 > @@ -223,14 +223,18 @@ namespace dr122 { // dr122: yes > // dr124: dup 201 > > // dr125: yes > -struct dr125_A { struct dr125_B {}; }; > +struct dr125_A { struct dr125_B {}; }; // expected-note {{here}} > dr125_A::dr125_B dr125_C(); > namespace dr125_B { dr125_A dr125_C(); } > namespace dr125 { > struct X { > friend dr125_A::dr125_B (::dr125_C)(); // ok > friend dr125_A (::dr125_B::dr125_C)(); // ok > - friend dr125_A::dr125_B::dr125_C(); // expected-error {{requires a > type specifier}} > + friend dr125_A::dr125_B::dr125_C(); // expected-error {{did you mean > the constructor name 'dr125_B'?}} > + // expected-warning@-1 {{missing exception specification}} > +#if __cplusplus >= 201103L > + // expected-error@-3 {{follows constexpr declaration}} expected-note@-10 > {{here}} > +#endif > }; > } > > > Modified: cfe/trunk/test/Parser/cxx-decl.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-decl.cpp?rev=192644&r1=192643&r2=192644&view=diff > > ============================================================================== > --- cfe/trunk/test/Parser/cxx-decl.cpp (original) > +++ cfe/trunk/test/Parser/cxx-decl.cpp Mon Oct 14 19:00:26 2013 > @@ -223,6 +223,15 @@ void foo() { > } > } > > +namespace PR17567 { > + struct Foobar { // expected-note 2{{declared here}} > + FooBar(); // expected-error {{missing return type for function > 'FooBar'; did you mean the constructor name 'Foobar'?}} > + ~FooBar(); // expected-error {{expected the class name after '~' to > name a destructor}} > + }; > + FooBar::FooBar() {} // expected-error {{undeclared}} expected-error > {{missing return type}} > + FooBar::~FooBar() {} // expected-error {{undeclared}} expected-error > {{expected the class name}} > +} > + > // PR8380 > extern "" // expected-error {{unknown linkage language}} > test6a { ;// expected-error {{C++ requires a type specifier for all > declarations}} \ > > Modified: cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp?rev=192644&r1=192643&r2=192644&view=diff > > ============================================================================== > --- cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp (original) > +++ cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp Mon Oct 14 19:00:26 2013 > @@ -21,3 +21,10 @@ void NewBracedInitList() { > // A warning on this would be sufficient once we can handle it > correctly. > new int {}; // expected-error {{}} > } > + > +struct Auto { > + static int n; > +}; > +auto Auto::n = 0; // expected-warning {{'auto' type specifier is a C++11 > extension}} > +auto Auto::m = 0; // expected-error {{no member named 'm' in 'Auto'}} > + // expected-warning@-1 {{'auto' type specifier is a > C++11 extension}} > > Modified: cfe/trunk/test/SemaCXX/nested-name-spec.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nested-name-spec.cpp?rev=192644&r1=192643&r2=192644&view=diff > > ============================================================================== > --- cfe/trunk/test/SemaCXX/nested-name-spec.cpp (original) > +++ cfe/trunk/test/SemaCXX/nested-name-spec.cpp Mon Oct 14 19:00:26 2013 > @@ -167,9 +167,7 @@ void N::f() { } // okay > struct Y; // expected-note{{forward declaration of 'Y'}} > Y::foo y; // expected-error{{incomplete type 'Y' named in nested name > specifier}} > > -X::X() : a(5) { } // expected-error{{use of undeclared identifier 'X'}} \ > - // expected-error{{C++ requires a type specifier for all > declarations}} \ > - // expected-error{{only constructors take base initializers}} > +X::X() : a(5) { } // expected-error{{use of undeclared identifier 'X'}} > > struct foo_S { > static bool value; > > Modified: cfe/trunk/test/SemaTemplate/alias-nested-nontag.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/alias-nested-nontag.cpp?rev=192644&r1=192643&r2=192644&view=diff > > ============================================================================== > --- cfe/trunk/test/SemaTemplate/alias-nested-nontag.cpp (original) > +++ cfe/trunk/test/SemaTemplate/alias-nested-nontag.cpp Mon Oct 14 > 19:00:26 2013 > @@ -2,5 +2,4 @@ > > template<typename T> using Id = T; // expected-note {{type alias template > 'Id' declared here}} > struct U { static Id<int> V; }; > -Id<int> ::U::V; // expected-error {{type 'Id<int>' (aka 'int') cannot be > used prior to '::' because it has no members}} \ > - expected-error {{C++ requires a type specifier}} > +Id<int> ::U::V; // expected-error {{type 'Id<int>' (aka 'int') cannot be > used prior to '::' because it has no members}} > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
