forked from OSchip/llvm-project
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:
parent
984cfe8322
commit
943c440455
|
@ -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>;
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 ',' '...'
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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'}}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue