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'.

llvm-svn: 160998
This commit is contained in:
Richard Smith 2012-07-30 21:30:52 +00:00
parent 984cfe8322
commit 943c440455
18 changed files with 186 additions and 119 deletions

View File

@ -415,9 +415,6 @@ def err_expected_init_in_condition_lparen : Error<
"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>;

View File

@ -158,6 +158,11 @@ def warn_redefinition_in_param_list : Warning<
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<

View File

@ -1643,11 +1643,11 @@ private:
/// 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 @@ private:
void ParseFunctionDeclarator(Declarator &D,
ParsedAttributes &attrs,
BalancedDelimiterTracker &Tracker,
bool IsAmbiguous,
bool RequiresArg = false);
bool isFunctionDeclaratorIdentifierList();
void ParseFunctionDeclaratorIdentifierList(

View File

@ -1104,6 +1104,9 @@ struct DeclaratorChunk {
/// 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 @@ struct DeclaratorChunk {
/// 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,

View File

@ -4318,17 +4318,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// 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 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// 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::ParseParenDeclarator(Declarator &D) {
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 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// 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,

View File

@ -2415,7 +2415,7 @@ ExprResult Parser::ParseBlockLiteralExpression() {
} 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(),

View File

@ -804,7 +804,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
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 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
ParsedAttributes Attr(AttrFactory);
D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true,
/*isVariadic=*/false,
/*isAmbiguous=*/false,
/*EllipsisLoc=*/SourceLocation(),
/*Params=*/0, /*NumParams=*/0,
/*TypeQuals=*/0,

View File

@ -671,7 +671,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
// 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 @@ Parser::TryParseDeclarationSpecifier(bool *HasMissingTypename) {
/// '(' 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 @@ bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) {
}
}
SourceLocation TPLoc = Tok.getLocation();
PA.Revert();
if (IsAmbiguous && TPR == TPResult::Ambiguous())
*IsAmbiguous = true;
// 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;
}
return TPR == TPResult::True();
return TPR != TPResult::False();
}
/// parameter-declaration-clause:
@ -1344,7 +1334,7 @@ Parser::TPResult
Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) {
if (Tok.is(tok::r_paren))
return TPResult::True();
return TPResult::Ambiguous();
// parameter-declaration-list[opt] '...'[opt]
// parameter-declaration-list ',' '...'

View File

@ -145,6 +145,7 @@ CXXScopeSpec::getWithLocInContext(ASTContext &Context) const {
/// 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 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
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;

View File

@ -5245,58 +5245,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
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 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
(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(),

View File

@ -554,7 +554,8 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
// ...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 @@ static void checkQualifiedFunction(Sema &S, QualType T,
<< 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 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
<< (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);

View File

@ -7,6 +7,7 @@ struct S {
struct T {
T();
T(S, S);
int n;
};
@ -30,26 +31,44 @@ S F2();
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 @@ namespace N {
// 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}}
}
}

View File

@ -35,7 +35,8 @@ void f(X *noreturn) {
[[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.

View File

@ -7,7 +7,7 @@ void test() {
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'}}

View File

@ -10,9 +10,9 @@ int returns_an_int();
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 @@ struct S5 {
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>

View File

@ -22,10 +22,10 @@ void f() {
(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();

View File

@ -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}}
}

View File

@ -22,8 +22,8 @@ typename N::C::type *ip3 = &i; // expected-error{{typename specifier refers to n
// 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;