Tweak to r147599 for PR10828: Move the check from the parser into sema, and use
the Semantic Powers to only warn on class types (or dependent types), where the
constructor or destructor could do something interesting.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147642 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index bd30f48..919d105 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -389,9 +389,6 @@
def warn_parens_disambiguated_as_function_decl : Warning<
"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/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 3a11d14..e15352b 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -112,6 +112,9 @@
InGroup<UnusedExceptionParameter>, DefaultIgnore;
def warn_decl_in_param_list : Warning<
"declaration of %0 will not be visible outside of this function">;
+def warn_empty_parens_are_function_decl : Warning<
+ "empty parentheses interpreted as a function declaration">,
+ InGroup<VexingParse>;
def warn_unused_function : Warning<"unused function %0">,
InGroup<UnusedFunction>, DefaultIgnore;
def warn_unused_member_function : Warning<"unused member function %0">,
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index d3c8211..ee4a51e 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1111,21 +1111,6 @@
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/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 8353c08..3e9e66d 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -4904,6 +4904,25 @@
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->isDependentType() || T->isRecordType()) &&
+ 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);
+ }
+ }
+
// C++ [dcl.fct.spec]p5:
// The virtual specifier shall only be used in declarations of
// nonstatic class member functions that appear within a
diff --git a/test/CXX/basic/basic.link/p9.cpp b/test/CXX/basic/basic.link/p9.cpp
index c895253..d8969ba 100644
--- a/test/CXX/basic/basic.link/p9.cpp
+++ b/test/CXX/basic/basic.link/p9.cpp
@@ -6,5 +6,5 @@
// First bullet: two names with external linkage that refer to
// different kinds of entities.
void f() {
- int N(); // expected-error{{redefinition}} expected-warning{{interpreted as a function declaration}}
+ int N(); // expected-error{{redefinition}}
}
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 b1dcf4d..303df8d 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 test2 {
namespace ns { void foo(); } // expected-note 2 {{target of using declaration}}
void test0() {
- int foo(); // expected-note {{conflicting declaration}} expected-warning{{function declaration}}
+ int foo(); // expected-note {{conflicting 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}} expected-warning{{function declaration}}
+ int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}}
}
}
@@ -39,7 +39,7 @@
namespace ns { void foo(); } // expected-note 2 {{target of using declaration}}
class Test0 {
void test() {
- int foo(); // expected-note {{conflicting declaration}} expected-warning{{function declaration}}
+ int foo(); // expected-note {{conflicting declaration}}
using ns::foo; // expected-error {{target of using declaration conflicts with declaration already in scope}}
}
};
@@ -47,7 +47,7 @@
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}} expected-warning{{function declaration}}
+ int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}}
}
};
}
@@ -56,7 +56,7 @@
namespace ns { void foo(); } // expected-note 2 {{target of using declaration}}
template <typename> class Test0 {
void test() {
- int foo(); // expected-note {{conflicting declaration}} expected-warning{{function declaration}}
+ int foo(); // expected-note {{conflicting declaration}}
using ns::foo; // expected-error {{target of using declaration conflicts with declaration already in scope}}
}
};
@@ -64,7 +64,7 @@
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}} expected-warning{{function declaration}}
+ int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}}
}
};
}
diff --git a/test/SemaCXX/decl-expr-ambiguity.cpp b/test/SemaCXX/decl-expr-ambiguity.cpp
index 555e89c..4a93b9a 100644
--- a/test/SemaCXX/decl-expr-ambiguity.cpp
+++ b/test/SemaCXX/decl-expr-ambiguity.cpp
@@ -26,9 +26,13 @@
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();
+ S d3(); // expected-warning {{empty parentheses interpreted as a function declaration}}
+ S d3v(void);
+ typedef S d3t();
+ extern S f3();
+ __typeof(*T()) f4(); // expected-warning {{empty parentheses interpreted as a function declaration}}
+ S multi1,
+ multi2(); // expected-warning {{empty parentheses interpreted as a function declaration}}
T(d)[5]; // expected-error {{redefinition of 'd'}}
typeof(int[])(f) = { 1, 2 }; // expected-error {{extension used}}
void(b)(int);