r192644 - PR17567: Improve diagnostic for a mistyped constructor name. If we see something

Sean Silva silvas at purdue.edu
Mon Oct 14 18:16:29 PDT 2013


Awesome! Thanks Richard!

-- Sean Silva


On Mon, Oct 14, 2013 at 8:00 PM, Richard Smith
<richard-llvm at metafoo.co.uk>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 at -1 {{missing exception specification}}
> +#if __cplusplus >= 201103L
> +    // expected-error at -3 {{follows constexpr declaration}} expected-note at -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 at -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
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131014/90d65fc8/attachment.html>


More information about the cfe-commits mailing list