aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-01-05 04:12:21 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-01-05 04:12:21 +0000
commitcb7709c06027448c754dd03e2e521d82d04818bf (patch)
tree4566bb699a7b846fa7bb7893440d6e45278f3e65
parentec9ea7200718478e8a976529defbe21942a11c9c (diff)
PR10828: Produce a warning when a no-arguments function is declared in block
scope, when no other indication is provided that the user intended to declare a function rather than a variable. Remove some false positives from the existing 'parentheses disambiguated as a function' warning by suppressing it when the declaration is marked as 'typedef' or 'extern'. Add a new warning group -Wvexing-parse containing both of these warnings. The new warning is enabled by default; despite a number of false positives (and one bug) in clang's test-suite, I have only found genuine bugs with it when running it over a significant quantity of real C++ code. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147599 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticGroups.td1
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td6
-rw-r--r--include/clang/Sema/DeclSpec.h7
-rw-r--r--lib/Parse/ParseDecl.cpp15
-rw-r--r--test/CXX/basic/basic.link/p9.cpp3
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp13
-rw-r--r--test/Misc/warning-flags.c3
-rw-r--r--test/SemaCXX/conditional-expr.cpp4
-rw-r--r--test/SemaCXX/decl-expr-ambiguity.cpp9
-rw-r--r--test/SemaTemplate/class-template-ctor-initializer.cpp2
10 files changed, 46 insertions, 17 deletions
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index c54abaa1dc..9c03580413 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -231,6 +231,7 @@ def OverridingMethodMismatch : DiagGroup<"overriding-method-mismatch">;
def : DiagGroup<"variadic-macros">;
def VariadicMacros : DiagGroup<"variadic-macros">;
def VectorConversions : DiagGroup<"vector-conversions">; // clang specific
+def VexingParse : DiagGroup<"vexing-parse">;
def VLA : DiagGroup<"vla">;
def VolatileRegisterVar : DiagGroup<"volatile-register-var">;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 90d4721603..bd30f486b7 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -387,7 +387,11 @@ def err_expected_lparen_after_type : Error<
def err_expected_equal_after_declarator : Error<
"expected '=' after declarator">;
def warn_parens_disambiguated_as_function_decl : Warning<
- "parentheses were disambiguated as a function declarator">;
+ "parentheses were disambiguated as a function declarator">,
+ InGroup<VexingParse>;
+def warn_empty_parens_are_function_decl : Warning<
+ "empty parentheses interpreted as a function declaration">,
+ InGroup<VexingParse>;
def warn_dangling_else : Warning<
"add explicit braces to avoid dangling else">,
InGroup<DanglingElse>;
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 44823c8f93..a601210bf4 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -1626,6 +1626,13 @@ public:
bool mayBeFollowedByCXXDirectInit() const {
if (hasGroupingParens()) return false;
+ if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
+ return false;
+
+ if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern &&
+ Context != FileContext)
+ return false;
+
switch (Context) {
case FileContext:
case BlockContext:
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index ee4a51e184..d3c8211372 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1111,6 +1111,21 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
if (FirstDecl)
DeclsInGroup.push_back(FirstDecl);
+ // In C++, "T var();" at block scope 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 (getLang().CPlusPlus && Context != Declarator::FileContext &&
+ D.getNumTypeObjects() == 1 && D.isFunctionDeclarator() &&
+ D.getDeclSpec().getStorageClassSpecAsWritten()
+ == DeclSpec::SCS_unspecified &&
+ D.getDeclSpec().getTypeSpecType() != DeclSpec::TST_void) {
+ DeclaratorChunk &C = D.getTypeObject(0);
+ if (C.Fun.NumArgs == 0 && !C.Fun.isVariadic && !C.Fun.TrailingReturnType &&
+ C.Fun.getExceptionSpecType() == EST_None)
+ Diag(C.Loc, diag::warn_empty_parens_are_function_decl)
+ << SourceRange(C.Loc, C.EndLoc);
+ }
+
bool ExpectSemi = Context != Declarator::ForContext;
// If we don't have a comma, it is either the end of the list (a ';') or an
diff --git a/test/CXX/basic/basic.link/p9.cpp b/test/CXX/basic/basic.link/p9.cpp
index bd16b02d7b..c895253c68 100644
--- a/test/CXX/basic/basic.link/p9.cpp
+++ b/test/CXX/basic/basic.link/p9.cpp
@@ -6,6 +6,5 @@ namespace N { } // expected-note{{here}}
// First bullet: two names with external linkage that refer to
// different kinds of entities.
void f() {
- int N(); // expected-error{{redefinition}}
+ int N(); // expected-error{{redefinition}} expected-warning{{interpreted as a function declaration}}
}
-
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp
index 63b302265e..b1dcf4d015 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp
@@ -25,13 +25,13 @@ namespace test1 {
namespace test2 {
namespace ns { void foo(); } // expected-note 2 {{target of using declaration}}
void test0() {
- int foo(); // expected-note {{conflicting declaration}}
+ int foo(); // expected-note {{conflicting declaration}} expected-warning{{function declaration}}
using ns::foo; // expected-error {{target of using declaration conflicts with declaration already in scope}}
}
void test1() {
using ns::foo; //expected-note {{using declaration}}
- int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}}
+ int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}} expected-warning{{function declaration}}
}
}
@@ -39,7 +39,7 @@ namespace test3 {
namespace ns { void foo(); } // expected-note 2 {{target of using declaration}}
class Test0 {
void test() {
- int foo(); // expected-note {{conflicting declaration}}
+ int foo(); // expected-note {{conflicting declaration}} expected-warning{{function declaration}}
using ns::foo; // expected-error {{target of using declaration conflicts with declaration already in scope}}
}
};
@@ -47,7 +47,7 @@ namespace test3 {
class Test1 {
void test() {
using ns::foo; //expected-note {{using declaration}}
- int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}}
+ int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}} expected-warning{{function declaration}}
}
};
}
@@ -56,7 +56,7 @@ namespace test4 {
namespace ns { void foo(); } // expected-note 2 {{target of using declaration}}
template <typename> class Test0 {
void test() {
- int foo(); // expected-note {{conflicting declaration}}
+ int foo(); // expected-note {{conflicting declaration}} expected-warning{{function declaration}}
using ns::foo; // expected-error {{target of using declaration conflicts with declaration already in scope}}
}
};
@@ -64,7 +64,7 @@ namespace test4 {
template <typename> class Test1 {
void test() {
using ns::foo; //expected-note {{using declaration}}
- int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}}
+ int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}} expected-warning{{function declaration}}
}
};
}
@@ -91,4 +91,3 @@ namespace test5 {
template class Test0<int>;
template class Test1<int>; // expected-note {{in instantiation of member function}}
}
-
diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
index 5e05e0b87a..42c09cbe7d 100644
--- a/test/Misc/warning-flags.c
+++ b/test/Misc/warning-flags.c
@@ -17,7 +17,7 @@ This test serves two purposes:
The list of warnings below should NEVER grow. It should gradually shrink to 0.
-CHECK: Warnings without flags (268):
+CHECK: Warnings without flags (267):
CHECK-NEXT: ext_anon_param_requires_type_specifier
CHECK-NEXT: ext_anonymous_struct_union_qualified
CHECK-NEXT: ext_array_init_copy
@@ -211,7 +211,6 @@ CHECK-NEXT: warn_octal_escape_too_large
CHECK-NEXT: warn_odr_tag_type_inconsistent
CHECK-NEXT: warn_on_superclass_use
CHECK-NEXT: warn_param_default_argument_redefinition
-CHECK-NEXT: warn_parens_disambiguated_as_function_decl
CHECK-NEXT: warn_partial_specs_not_deducible
CHECK-NEXT: warn_pointer_attribute_wrong_type
CHECK-NEXT: warn_pp_convert_lhs_to_positive
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
index 5648d022b5..3cfddb3a41 100644
--- a/test/SemaCXX/conditional-expr.cpp
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -96,8 +96,8 @@ void test()
(void)(i1 ? BadDerived() : BadBase());
// b2.1 (hierarchy stuff)
- const Base constret();
- const Derived constder();
+ const Base constret(); // expected-warning {{interpreted as a function declaration}}
+ const Derived constder(); // expected-warning {{interpreted as a function declaration}}
// should use const overload
A a1((i1 ? constret() : Base()).trick());
A a2((i1 ? Base() : constret()).trick());
diff --git a/test/SemaCXX/decl-expr-ambiguity.cpp b/test/SemaCXX/decl-expr-ambiguity.cpp
index 1ddff8058a..555e89ca7d 100644
--- a/test/SemaCXX/decl-expr-ambiguity.cpp
+++ b/test/SemaCXX/decl-expr-ambiguity.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -pedantic-errors %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic-errors %s
void f() {
int a;
@@ -24,10 +24,15 @@ void f() {
// 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));
+ T d3(); // expected-warning {{empty parentheses interpreted as a function declaration}}
+ typedef T d3t();
+ extern T f3();
T(d)[5]; // expected-error {{redefinition of 'd'}}
typeof(int[])(f) = { 1, 2 }; // expected-error {{extension used}}
void(b)(int);
- int(d2) __attribute__(());
+ int(d2) __attribute__(());
if (int(a)=1) {}
int(d3(int()));
}
diff --git a/test/SemaTemplate/class-template-ctor-initializer.cpp b/test/SemaTemplate/class-template-ctor-initializer.cpp
index 81a5e2b9c6..44bb4bda79 100644
--- a/test/SemaTemplate/class-template-ctor-initializer.cpp
+++ b/test/SemaTemplate/class-template-ctor-initializer.cpp
@@ -49,7 +49,7 @@ namespace PR7259 {
int
main (void)
{
- Final final();
+ Final final;
return 0;
}
}