[cfe-commits] r160998 - in /cfe/trunk: include/clang/Basic/ include/clang/Parse/ include/clang/Sema/ lib/Parse/ lib/Sema/ test/FixIt/ test/Parser/ test/SemaCXX/ test/SemaObjCXX/ test/SemaTemplate/

Richard Smith richard-llvm at metafoo.co.uk
Mon Jul 30 14:30:52 PDT 2012


Author: rsmith
Date: Mon Jul 30 16:30:52 2012
New Revision: 160998

URL: http://llvm.org/viewvc/llvm-project?rev=160998&view=rev
Log:
Improvements to vexing-parse warnings. Make the no-parameters case more
accurate by asking the parser whether there was an ambiguity rather than trying
to reverse-engineer it from the DeclSpec. Make the with-parameters case have
better diagnostics by using semantic information to drive the warning,
improving the diagnostics and adding a fixit.

Patch by Nikola Smiljanic. Some minor changes by me to suppress diagnostics for
declarations of the form 'T (*x)(...)', which seem to have a very high false
positive rate, and to reduce indentation in 'warnAboutAmbiguousFunction'.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/DeclSpec.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Parse/ParseTentative.cpp
    cfe/trunk/lib/Sema/DeclSpec.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/FixIt/fixit-vexing-parse.cpp
    cfe/trunk/test/Parser/objcxx11-attributes.mm
    cfe/trunk/test/SemaCXX/condition.cpp
    cfe/trunk/test/SemaCXX/dcl_ambig_res.cpp
    cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp
    cfe/trunk/test/SemaObjCXX/protocol-lookup.mm
    cfe/trunk/test/SemaTemplate/typename-specifier.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Mon Jul 30 16:30:52 2012
@@ -415,9 +415,6 @@
   "variable declaration in condition cannot have a parenthesized initializer">;
 def err_extraneous_rparen_in_condition : Error<
   "extraneous ')' after condition, expected a statement">;
-def warn_parens_disambiguated_as_function_decl : Warning<
-  "parentheses were disambiguated as a function declarator">,
-  InGroup<VexingParse>;
 def warn_dangling_else : Warning<
   "add explicit braces to avoid dangling else">,
   InGroup<DanglingElse>;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jul 30 16:30:52 2012
@@ -158,6 +158,11 @@
 def warn_empty_parens_are_function_decl : Warning<
   "empty parentheses interpreted as a function declaration">,
   InGroup<VexingParse>;
+def warn_parens_disambiguated_as_function_declaration : Warning<
+  "parentheses were disambiguated as a function declaration">,
+  InGroup<VexingParse>;
+def note_additional_parens_for_variable_declaration : Note<
+  "add a pair of parentheses to declare a variable">;
 def note_empty_parens_function_call : Note<
   "change this ',' to a ';' to call %0">;
 def note_empty_parens_default_ctor : Note<

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Jul 30 16:30:52 2012
@@ -1643,11 +1643,11 @@
   /// isCXXFunctionDeclarator - Disambiguates between a function declarator or
   /// a constructor-style initializer, when parsing declaration statements.
   /// Returns true for function declarator and false for constructor-style
-  /// initializer. If 'warnIfAmbiguous' is true a warning will be emitted to
-  /// indicate that the parens were disambiguated as function declarator.
+  /// initializer. Sets 'IsAmbiguous' to true to indicate that this declaration 
+  /// might be a constructor-style initializer.
   /// If during the disambiguation process a parsing error is encountered,
   /// the function returns true to let the declaration parsing code handle it.
-  bool isCXXFunctionDeclarator(bool warnIfAmbiguous);
+  bool isCXXFunctionDeclarator(bool *IsAmbiguous = 0);
 
   /// isCXXConditionDeclaration - Disambiguates between a declaration or an
   /// expression for a condition of a if/switch/while/for statement.
@@ -1903,6 +1903,7 @@
   void ParseFunctionDeclarator(Declarator &D,
                                ParsedAttributes &attrs,
                                BalancedDelimiterTracker &Tracker,
+                               bool IsAmbiguous,
                                bool RequiresArg = false);
   bool isFunctionDeclaratorIdentifierList();
   void ParseFunctionDeclaratorIdentifierList(

Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Mon Jul 30 16:30:52 2012
@@ -1104,6 +1104,9 @@
     /// contains the location of the ellipsis.
     unsigned isVariadic : 1;
 
+    /// Can this declaration be a constructor-style initializer?
+    unsigned isAmbiguous : 1;
+
     /// \brief Whether the ref-qualifier (if any) is an lvalue reference.
     /// Otherwise, it's an rvalue reference.
     unsigned RefQualifierIsLValueRef : 1;
@@ -1356,6 +1359,7 @@
   /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
   /// "TheDeclarator" is the declarator that this will be added to.
   static DeclaratorChunk getFunction(bool hasProto, bool isVariadic,
+                                     bool isAmbiguous,
                                      SourceLocation EllipsisLoc,
                                      ParamInfo *ArgInfo, unsigned NumArgs,
                                      unsigned TypeQuals, 

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jul 30 16:30:52 2012
@@ -4318,17 +4318,14 @@
       // The paren may be part of a C++ direct initializer, eg. "int x(1);".
       // In such a case, check if we actually have a function declarator; if it
       // is not, the declarator has been fully parsed.
-      if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) {
-        // When not in file scope, warn for ambiguous function declarators, just
-        // in case the author intended it as a variable definition.
-        bool warnIfAmbiguous = D.getContext() != Declarator::FileContext;
-        if (!isCXXFunctionDeclarator(warnIfAmbiguous))
-          break;
-      }
+      bool IsAmbiguous = false;
+      if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit() &&
+          !isCXXFunctionDeclarator(&IsAmbiguous))
+        break;
       ParsedAttributes attrs(AttrFactory);
       BalancedDelimiterTracker T(*this, tok::l_paren);
       T.consumeOpen();
-      ParseFunctionDeclarator(D, attrs, T);
+      ParseFunctionDeclarator(D, attrs, T, IsAmbiguous);
       PrototypeScope.Exit();
     } else if (Tok.is(tok::l_square)) {
       ParseBracketDeclarator(D);
@@ -4445,7 +4442,7 @@
   // function prototype scope, including parameter declarators.
   ParseScope PrototypeScope(this,
                             Scope::FunctionPrototypeScope|Scope::DeclScope);
-  ParseFunctionDeclarator(D, attrs, T, RequiresArg);
+  ParseFunctionDeclarator(D, attrs, T, false, RequiresArg);
   PrototypeScope.Exit();
 }
 
@@ -4471,6 +4468,7 @@
 void Parser::ParseFunctionDeclarator(Declarator &D,
                                      ParsedAttributes &FirstArgAttrs,
                                      BalancedDelimiterTracker &Tracker,
+                                     bool IsAmbiguous,
                                      bool RequiresArg) {
   assert(getCurScope()->isFunctionPrototypeScope() &&
          "Should call from a Function scope");
@@ -4588,7 +4586,7 @@
   // Remember that we parsed a function type, and remember the attributes.
   D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto,
                                              /*isVariadic=*/EllipsisLoc.isValid(),
-                                             EllipsisLoc,
+                                             IsAmbiguous, EllipsisLoc,
                                              ParamInfo.data(), ParamInfo.size(),
                                              DS.getTypeQualifiers(),
                                              RefQualifierIsLValueRef,

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Mon Jul 30 16:30:52 2012
@@ -2415,7 +2415,7 @@
   } else {
     // Otherwise, pretend we saw (void).
     ParsedAttributes attrs(AttrFactory);
-    ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
+    ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, false,
                                                        SourceLocation(),
                                                        0, 0, 0,
                                                        true, SourceLocation(),

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Mon Jul 30 16:30:52 2012
@@ -804,7 +804,7 @@
 
     D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true,
                                            /*isVariadic=*/EllipsisLoc.isValid(),
-                                           EllipsisLoc,
+                                           /*isAmbiguous=*/false, EllipsisLoc,
                                            ParamInfo.data(), ParamInfo.size(),
                                            DS.getTypeQualifiers(),
                                            /*RefQualifierIsLValueRef=*/true,
@@ -849,6 +849,7 @@
     ParsedAttributes Attr(AttrFactory);
     D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true,
                      /*isVariadic=*/false,
+                     /*isAmbiguous=*/false,
                      /*EllipsisLoc=*/SourceLocation(),
                      /*Params=*/0, /*NumParams=*/0,
                      /*TypeQuals=*/0,

Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Mon Jul 30 16:30:52 2012
@@ -671,7 +671,7 @@
       // initializer that follows the declarator. Note that ctor-style
       // initializers are not possible in contexts where abstract declarators
       // are allowed.
-      if (!mayBeAbstract && !isCXXFunctionDeclarator(false/*warnIfAmbiguous*/))
+      if (!mayBeAbstract && !isCXXFunctionDeclarator())
         break;
 
       // direct-declarator '(' parameter-declaration-clause ')'
@@ -1267,7 +1267,7 @@
 /// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
 ///         exception-specification[opt]
 ///
-bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) {
+bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) {
 
   // C++ 8.2p1:
   // The ambiguity arising from the similarity between a function-style cast and
@@ -1304,23 +1304,13 @@
     }
   }
 
-  SourceLocation TPLoc = Tok.getLocation();
   PA.Revert();
 
-  // In case of an error, let the declaration parsing code handle it.
-  if (TPR == TPResult::Error())
-    return true;
-
-  if (TPR == TPResult::Ambiguous()) {
-    // Function declarator has precedence over constructor-style initializer.
-    // Emit a warning just in case the author intended a variable definition.
-    if (warnIfAmbiguous)
-      Diag(Tok, diag::warn_parens_disambiguated_as_function_decl)
-        << SourceRange(Tok.getLocation(), TPLoc);
-    return true;
-  }
+  if (IsAmbiguous && TPR == TPResult::Ambiguous())
+    *IsAmbiguous = true;
 
-  return TPR == TPResult::True();
+  // In case of an error, let the declaration parsing code handle it.
+  return TPR != TPResult::False();
 }
 
 /// parameter-declaration-clause:
@@ -1344,7 +1334,7 @@
 Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) {
 
   if (Tok.is(tok::r_paren))
-    return TPResult::True();
+    return TPResult::Ambiguous();
 
   //   parameter-declaration-list[opt] '...'[opt]
   //   parameter-declaration-list ',' '...'

Modified: cfe/trunk/lib/Sema/DeclSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/DeclSpec.cpp?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/DeclSpec.cpp (original)
+++ cfe/trunk/lib/Sema/DeclSpec.cpp Mon Jul 30 16:30:52 2012
@@ -145,6 +145,7 @@
 /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
 /// "TheDeclarator" is the declarator that this will be added to.
 DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
+                                             bool isAmbiguous,
                                              SourceLocation EllipsisLoc,
                                              ParamInfo *ArgInfo,
                                              unsigned NumArgs,
@@ -173,6 +174,7 @@
   I.Fun.AttrList                = 0;
   I.Fun.hasPrototype            = hasProto;
   I.Fun.isVariadic              = isVariadic;
+  I.Fun.isAmbiguous             = isAmbiguous;
   I.Fun.EllipsisLoc             = EllipsisLoc.getRawEncoding();
   I.Fun.DeleteArgInfo           = false;
   I.Fun.TypeQuals               = TypeQuals;

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Jul 30 16:30:52 2012
@@ -5245,58 +5245,6 @@
         FunctionTemplate->setInvalidDecl();
     }
 
-    // If we see "T var();" at block scope, where T is a class type, it is
-    // probably an attempt to initialize a variable, not a function declaration.
-    // We don't catch this case earlier, since there is no ambiguity here.
-    if (!FunctionTemplate && D.getFunctionDefinitionKind() == FDK_Declaration &&
-        CurContext->isFunctionOrMethod() &&
-        D.getNumTypeObjects() == 1 && D.isFunctionDeclarator() &&
-        D.getDeclSpec().getStorageClassSpecAsWritten()
-          == DeclSpec::SCS_unspecified) {
-      QualType T = R->getAs<FunctionType>()->getResultType();
-      DeclaratorChunk &C = D.getTypeObject(0);
-      if (!T->isVoidType() && C.Fun.NumArgs == 0 && !C.Fun.isVariadic &&
-          !C.Fun.hasTrailingReturnType() &&
-          C.Fun.getExceptionSpecType() == EST_None) {
-        SourceRange ParenRange(C.Loc, C.EndLoc);
-        Diag(C.Loc, diag::warn_empty_parens_are_function_decl) << ParenRange;
-
-        // If the declaration looks like:
-        //   T var1,
-        //   f();
-        // and name lookup finds a function named 'f', then the ',' was
-        // probably intended to be a ';'.
-        if (!D.isFirstDeclarator() && D.getIdentifier()) {
-          FullSourceLoc Comma(D.getCommaLoc(), SourceMgr);
-          FullSourceLoc Name(D.getIdentifierLoc(), SourceMgr);
-          if (Comma.getFileID() != Name.getFileID() ||
-              Comma.getSpellingLineNumber() != Name.getSpellingLineNumber()) {
-            LookupResult Result(*this, D.getIdentifier(), SourceLocation(),
-                                LookupOrdinaryName);
-            if (LookupName(Result, S))
-              Diag(D.getCommaLoc(), diag::note_empty_parens_function_call)
-                << FixItHint::CreateReplacement(D.getCommaLoc(), ";") << NewFD;
-          }
-        }
-        const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
-        // Empty parens mean value-initialization, and no parens mean default
-        // initialization. These are equivalent if the default constructor is
-        // user-provided, or if zero-initialization is a no-op.
-        if (RD && RD->hasDefinition() &&
-            (RD->isEmpty() || RD->hasUserProvidedDefaultConstructor()))
-          Diag(C.Loc, diag::note_empty_parens_default_ctor)
-            << FixItHint::CreateRemoval(ParenRange);
-        else {
-          std::string Init = getFixItZeroInitializerForType(T);
-          if (Init.empty() && LangOpts.CPlusPlus0x)
-            Init = "{}";
-          if (!Init.empty())
-            Diag(C.Loc, diag::note_empty_parens_zero_initialize)
-              << FixItHint::CreateReplacement(ParenRange, Init);
-        }
-      }
-    }
-
     // C++ [dcl.fct.spec]p5:
     //   The virtual specifier shall only be used in declarations of
     //   nonstatic class member functions that appear within a
@@ -7915,10 +7863,10 @@
   (void)Error; // Silence warning.
   assert(!Error && "Error setting up implicit decl!");
   Declarator D(DS, Declarator::BlockContext);
-  D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0,
-                                             0, 0, true, SourceLocation(),
+  D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, false,
+                                             SourceLocation(), 0, 0, 0, true, 
+                                             SourceLocation(), SourceLocation(),
                                              SourceLocation(), SourceLocation(),
-                                             SourceLocation(),
                                              EST_None, SourceLocation(),
                                              0, 0, 0, 0, Loc, Loc, D),
                 DS.getAttributes(),

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Jul 30 16:30:52 2012
@@ -554,7 +554,8 @@
   // ...and *prepend* it to the declarator.
   declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction(
                              /*proto*/ true,
-                             /*variadic*/ false, SourceLocation(),
+                             /*variadic*/ false,
+                             /*ambiguous*/ false, SourceLocation(),
                              /*args*/ 0, 0,
                              /*type quals*/ 0,
                              /*ref-qualifier*/true, SourceLocation(),
@@ -2040,6 +2041,101 @@
     << getFunctionQualifiersAsString(T->castAs<FunctionProtoType>());
 }
 
+/// Produce an approprioate diagnostic for an ambiguity between a function
+/// declarator and a C++ direct-initializer.
+static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
+                                       DeclaratorChunk &DeclType, QualType RT) {
+  const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+  assert(FTI.isAmbiguous && "no direct-initializer / function ambiguity");
+
+  // If the return type is void there is no ambiguity.
+  if (RT->isVoidType())
+    return;
+
+  // An initializer for a non-class type can have at most one argument.
+  if (!RT->isRecordType() && FTI.NumArgs > 1)
+    return;
+
+  // An initializer for a reference must have exactly one argument.
+  if (RT->isReferenceType() && FTI.NumArgs != 1)
+    return;
+
+  // Only warn if this declarator is declaring a function at block scope, and
+  // doesn't have a storage class (such as 'extern') specified.
+  if (!D.isFunctionDeclarator() ||
+      D.getFunctionDefinitionKind() != FDK_Declaration ||
+      !S.CurContext->isFunctionOrMethod() ||
+      D.getDeclSpec().getStorageClassSpecAsWritten()
+        != DeclSpec::SCS_unspecified)
+    return;
+
+  // Inside a condition, a direct initializer is not permitted. We allow one to
+  // be parsed in order to give better diagnostics in condition parsing.
+  if (D.getContext() == Declarator::ConditionContext)
+    return;
+
+  SourceRange ParenRange(DeclType.Loc, DeclType.EndLoc);
+
+  // Declaration with parameters, eg. "T var(T());".
+  if (FTI.NumArgs > 0 &&
+      D.getContext() != Declarator::ConditionContext) {
+    S.Diag(DeclType.Loc,
+           diag::warn_parens_disambiguated_as_function_declaration)
+        << ParenRange;
+
+    SourceRange Range = FTI.ArgInfo[0].Param->getSourceRange();
+    SourceLocation B = Range.getBegin();
+    SourceLocation E = S.PP.getLocForEndOfToken(Range.getEnd());
+    // FIXME: Maybe we should suggest adding braces instead of parens
+    // in C++11 for classes that don't have an initializer_list constructor.
+    S.Diag(B, diag::note_additional_parens_for_variable_declaration)
+      << FixItHint::CreateInsertion(B, "(")
+      << FixItHint::CreateInsertion(E, ")");
+  }
+
+  // Declaration without parameters, eg. "T var();".
+  if (FTI.NumArgs == 0) {
+    S.Diag(DeclType.Loc, diag::warn_empty_parens_are_function_decl)
+      << ParenRange;
+
+    // If the declaration looks like:
+    //   T var1,
+    //   f();
+    // and name lookup finds a function named 'f', then the ',' was
+    // probably intended to be a ';'.
+    if (!D.isFirstDeclarator() && D.getIdentifier()) {
+      FullSourceLoc Comma(D.getCommaLoc(), S.SourceMgr);
+      FullSourceLoc Name(D.getIdentifierLoc(), S.SourceMgr);
+      if (Comma.getFileID() != Name.getFileID() ||
+          Comma.getSpellingLineNumber() != Name.getSpellingLineNumber()) {
+        LookupResult Result(S, D.getIdentifier(), SourceLocation(),
+        Sema::LookupOrdinaryName);
+        if (S.LookupName(Result, S.getCurScope()))
+          S.Diag(D.getCommaLoc(), diag::note_empty_parens_function_call)
+            << FixItHint::CreateReplacement(D.getCommaLoc(), ";")
+            << D.getIdentifier();
+      }
+    }
+    const CXXRecordDecl *RD = RT->getAsCXXRecordDecl();
+    // Empty parens mean value-initialization, and no parens mean
+    // default initialization. These are equivalent if the default
+    // constructor is user-provided or if zero-initialization is a
+    // no-op.
+    if (RD && RD->hasDefinition() &&
+        (RD->isEmpty() || RD->hasUserProvidedDefaultConstructor()))
+      S.Diag(DeclType.Loc, diag::note_empty_parens_default_ctor)
+        << FixItHint::CreateRemoval(ParenRange);
+    else {
+      std::string Init = S.getFixItZeroInitializerForType(RT);
+      if (Init.empty() && S.LangOpts.CPlusPlus0x)
+        Init = "{}";
+      if (!Init.empty())
+        S.Diag(DeclType.Loc, diag::note_empty_parens_zero_initialize)
+          << FixItHint::CreateReplacement(ParenRange, Init);
+    }
+  }
+}
+
 static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
                                                 QualType declSpecType,
                                                 TypeSourceInfo *TInfo) {
@@ -2272,6 +2368,11 @@
           << (D.getContext() == Declarator::AliasDeclContext ||
               D.getContext() == Declarator::AliasTemplateContext);
 
+      // If we see "T var();" or "T var(T());" at block scope, it is probably
+      // an attempt to initialize a variable, not a function declaration.
+      if (FTI.isAmbiguous)
+        warnAboutAmbiguousFunction(S, D, DeclType, T);
+
       if (!FTI.NumArgs && !FTI.isVariadic && !LangOpts.CPlusPlus) {
         // Simple void foo(), where the incoming T is the result type.
         T = Context.getFunctionNoProtoType(T);

Modified: cfe/trunk/test/FixIt/fixit-vexing-parse.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit-vexing-parse.cpp?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/test/FixIt/fixit-vexing-parse.cpp (original)
+++ cfe/trunk/test/FixIt/fixit-vexing-parse.cpp Mon Jul 30 16:30:52 2012
@@ -7,6 +7,7 @@
 
 struct T {
   T();
+  T(S, S);
   int n;
 };
 
@@ -30,26 +31,44 @@
 
 namespace N {
   void test() {
-    // CHECK: fix-it:"{{.*}}":{34:9-34:11}:" = {}"
+    // CHECK: fix-it:"{{.*}}":{35:9-35:11}:" = {}"
     S s1(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
 
-    // CHECK: fix-it:"{{.*}}":{38:9-38:10}:";"
-    // CHECK: fix-it:"{{.*}}":{39:7-39:9}:" = {}"
+    // CHECK: fix-it:"{{.*}}":{39:9-39:10}:";"
+    // CHECK: fix-it:"{{.*}}":{40:7-40:9}:" = {}"
     S s2, // expected-note {{change this ',' to a ';' to call 'F2'}}
     F2(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
 
-    // CHECK: fix-it:"{{.*}}":{43:9-43:11}:""
     // CHECK: fix-it:"{{.*}}":{44:9-44:11}:""
+    // CHECK: fix-it:"{{.*}}":{45:9-45:11}:""
     T t1(), // expected-warning {{function declaration}} expected-note {{remove parentheses}}
       t2(); // expected-warning {{function declaration}} expected-note {{remove parentheses}}
 
-    // CHECK: fix-it:"{{.*}}":{47:8-47:10}:" = {}"
+    // Suggest parentheses only around the first argument.
+    // CHECK: fix-it:"{{.*}}":{50:10-50:10}:"("
+    // CHECK: fix-it:"{{.*}}":{50:13-50:13}:")"
+    T t3(S(), S()); // expected-warning {{disambiguated as a function declaration}} expected-note {{add a pair of parentheses}}
+
+    // Check fixit position for pathological case
+    // CHECK: fix-it:"{{.*}}":{56:11-56:11}:"("
+    // CHECK: fix-it:"{{.*}}":{56:20-56:20}:")"
+    float k[1];
+    int l(int(k[0])); // expected-warning {{disambiguated as a function declaration}} expected-note {{add a pair of parentheses}}
+
+    // Don't emit warning and fixit because this must be a function declaration due to void return type.
+    typedef void VO;
+    VO m(int (*p)[4]);
+
+    // Don't emit warning and fixit because direct initializer is not permitted here.
+    if (int n(int())){} // expected-error {{function type is not allowed here}} expected-error {{condition must have an initializer}}
+
+    // CHECK: fix-it:"{{.*}}":{66:8-66:10}:" = {}"
     U u(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
 
-    // CHECK: fix-it:"{{.*}}":{50:8-50:10}:""
+    // CHECK: fix-it:"{{.*}}":{69:8-69:10}:""
     V v(); // expected-warning {{function declaration}} expected-note {{remove parentheses}}
 
-    // CHECK: fix-it:"{{.*}}":{53:8-53:10}:""
+    // CHECK: fix-it:"{{.*}}":{72:8-72:10}:""
     W w(); // expected-warning {{function declaration}} expected-note {{remove parentheses}}
 
     // TODO: Removing the parens here would not initialize U::n.
@@ -57,33 +76,33 @@
     // Maybe suggest removing the parens anyway?
     X x(); // expected-warning {{function declaration}}
 
-    // CHECK: fix-it:"{{.*}}":{61:11-61:13}:" = 0"
+    // CHECK: fix-it:"{{.*}}":{80:11-80:13}:" = 0"
     int n1(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
 
-    // CHECK: fix-it:"{{.*}}":{65:11-65:12}:";"
-    // CHECK: fix-it:"{{.*}}":{66:7-66:9}:" = 0"
+    // CHECK: fix-it:"{{.*}}":{84:11-84:12}:";"
+    // CHECK: fix-it:"{{.*}}":{85:7-85:9}:" = 0"
     int n2, // expected-note {{change this ',' to a ';' to call 'F1'}}
     F1(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
 
-    // CHECK: fix-it:"{{.*}}":{69:13-69:15}:" = 0.0"
+    // CHECK: fix-it:"{{.*}}":{88:13-88:15}:" = 0.0"
     double d(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
 
     typedef void *Ptr;
 
-    // CHECK: fix-it:"{{.*}}":{74:10-74:12}:" = 0"
+    // CHECK: fix-it:"{{.*}}":{93:10-93:12}:" = 0"
     Ptr p(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
 
 #define NULL 0
-    // CHECK: fix-it:"{{.*}}":{78:10-78:12}:" = NULL"
+    // CHECK: fix-it:"{{.*}}":{97:10-97:12}:" = NULL"
     Ptr p(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
 
-    // CHECK: fix-it:"{{.*}}":{81:11-81:13}:" = false"
+    // CHECK: fix-it:"{{.*}}":{100:11-100:13}:" = false"
     bool b(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
 
-    // CHECK: fix-it:"{{.*}}":{84:11-84:13}:" = '\\0'"
+    // CHECK: fix-it:"{{.*}}":{103:11-103:13}:" = '\\0'"
     char c(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
 
-    // CHECK: fix-it:"{{.*}}":{87:15-87:17}:" = L'\\0'"
+    // CHECK: fix-it:"{{.*}}":{106:15-106:17}:" = L'\\0'"
     wchar_t wc(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
   }
 }

Modified: cfe/trunk/test/Parser/objcxx11-attributes.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/objcxx11-attributes.mm?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/test/Parser/objcxx11-attributes.mm (original)
+++ cfe/trunk/test/Parser/objcxx11-attributes.mm Mon Jul 30 16:30:52 2012
@@ -35,7 +35,8 @@
   [[class, test(foo 'x' bar),,,]];
   [[bitand, noreturn]]; // expected-warning {{attribute noreturn cannot be specified on a statement}}
 
-  [[noreturn]]int(e)();
+  // FIXME: Suppress vexing parse warning
+  [[noreturn]]int(e)(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}} 
   int e2(); // expected-warning {{interpreted as a function declaration}} expected-note{{}}
 
   // A function taking a noreturn function.

Modified: cfe/trunk/test/SemaCXX/condition.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/condition.cpp?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/condition.cpp (original)
+++ cfe/trunk/test/SemaCXX/condition.cpp Mon Jul 30 16:30:52 2012
@@ -7,7 +7,7 @@
 
   typedef int arr[10];
   while (arr x=0) ; // expected-error {{an array type is not allowed here}} expected-error {{array initializer must be an initializer list}}
-  while (int f()=0) ; // expected-warning {{interpreted as a function declaration}} expected-note {{initializer}} expected-error {{a function type is not allowed here}}
+  while (int f()=0) ; // expected-error {{a function type is not allowed here}}
 
   struct S {} s;
   if (s) ++x; // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}

Modified: cfe/trunk/test/SemaCXX/dcl_ambig_res.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dcl_ambig_res.cpp?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/dcl_ambig_res.cpp (original)
+++ cfe/trunk/test/SemaCXX/dcl_ambig_res.cpp Mon Jul 30 16:30:52 2012
@@ -10,9 +10,9 @@
 
 void foo(double a) 
 { 
-  S w(int(a)); // expected-warning{{disambiguated}}
+  S w(int(a)); // expected-warning{{disambiguated as a function declaration}} expected-note{{add a pair of parentheses}} 
   w(17);
-  S x1(int()); // expected-warning{{disambiguated}}
+  S x1(int()); // expected-warning{{disambiguated as a function declaration}} expected-note{{add a pair of parentheses}} 
   x1(&returns_an_int);
   S y((int)a); 
   y.bar();
@@ -69,7 +69,7 @@
   static bool const value = false;
 };
 int foo8() {
-  int v(int(S5::value)); // expected-warning{{disambiguated}} expected-error{{parameter declarator cannot be qualified}}
+  int v(int(S5::value)); // expected-warning{{disambiguated as a function declaration}} expected-note{{add a pair of parentheses}} expected-error{{parameter declarator cannot be qualified}}
 }
 
 template<typename T>

Modified: cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp (original)
+++ cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp Mon Jul 30 16:30:52 2012
@@ -22,10 +22,10 @@
   (int())1; // expected-error {{C-style cast from 'int' to 'int ()' is not allowed}}
 
   // Declarations.
-  int fd(T(a)); // expected-warning {{parentheses were disambiguated as a function declarator}}
-  T(*d)(int(p)); // expected-warning {{parentheses were disambiguated as a function declarator}} expected-note {{previous definition is here}}
-  typedef T(*td)(int(p));
-  extern T(*tp)(int(p));
+  int fd(T(a)); // expected-warning {{disambiguated as a function declaration}} expected-note{{add a pair of parentheses}}
+  T(*d)(int(p)); // expected-note {{previous}}
+  typedef T td(int(p));
+  extern T tp(int(p));
   T d3(); // expected-warning {{empty parentheses interpreted as a function declaration}} expected-note {{replace parentheses with an initializer}}
   T d3v(void);
   typedef T d3t();

Modified: cfe/trunk/test/SemaObjCXX/protocol-lookup.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/protocol-lookup.mm?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/protocol-lookup.mm (original)
+++ cfe/trunk/test/SemaObjCXX/protocol-lookup.mm Mon Jul 30 16:30:52 2012
@@ -52,5 +52,5 @@
 void rdar8575095(id a) {
   [id<NSObject>(a) retain];
   id<NSObject> x(id<NSObject>(0));
-  id<NSObject> x2(id<NSObject>(y)); // expected-warning{{parentheses were disambiguated as a function declarator}}
+  id<NSObject> x2(id<NSObject>(y)); // expected-warning{{disambiguated as a function declaration}} expected-note{{add a pair of parentheses}}
 }

Modified: cfe/trunk/test/SemaTemplate/typename-specifier.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/typename-specifier.cpp?rev=160998&r1=160997&r2=160998&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/typename-specifier.cpp (original)
+++ cfe/trunk/test/SemaTemplate/typename-specifier.cpp Mon Jul 30 16:30:52 2012
@@ -22,8 +22,8 @@
 // expected-warning{{'typename' occurs outside of a template}}
 
 void test(double d) {
-  typename N::A::type f(typename N::A::type(a)); // expected-warning{{parentheses were disambiguated as a function declarator}} \
-  // expected-warning 2{{'typename' occurs outside of a template}}
+  typename N::A::type f(typename N::A::type(a)); // expected-warning{{disambiguated as a function declaration}} \
+  // expected-note{{add a pair of parentheses}} expected-warning 2{{'typename' occurs outside of a template}}
   int five = f(5);
   
   using namespace N;





More information about the cfe-commits mailing list