diff options
-rw-r--r-- | include/clang/AST/Expr.h | 5 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 26 | ||||
-rw-r--r-- | test/Sema/typo-correction.c | 15 |
3 files changed, 42 insertions, 4 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 3de7342882..bf4f3babbd 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -2577,6 +2577,11 @@ public: NumArgs = NewNumArgs; } + /// Bluntly set a new number of arguments without doing any checks whatsoever. + /// Only used during construction of a CallExpr in a few places in Sema. + /// FIXME: Find a way to remove it. + void setNumArgsUnsafe(unsigned NewNumArgs) { NumArgs = NewNumArgs; } + typedef ExprIterator arg_iterator; typedef ConstExprIterator const_arg_iterator; typedef llvm::iterator_range<arg_iterator> arg_range; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index db0c62630a..ff9393a56b 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -5676,18 +5676,36 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, } if (!getLangOpts().CPlusPlus) { + // Forget about the nulled arguments since typo correction + // do not handle them well. + TheCall->shrinkNumArgs(Args.size()); // C cannot always handle TypoExpr nodes in builtin calls and direct // function calls as their argument checking don't necessarily handle // dependent types properly, so make sure any TypoExprs have been // dealt with. ExprResult Result = CorrectDelayedTyposInExpr(TheCall); if (!Result.isUsable()) return ExprError(); + CallExpr *TheOldCall = TheCall; TheCall = dyn_cast<CallExpr>(Result.get()); + bool CorrectedTypos = TheCall != TheOldCall; if (!TheCall) return Result; - // TheCall at this point has max(Args.size(), NumParams) arguments, - // with extra arguments nulled. We don't want to introduce nulled - // arguments in Args and so we only take the first Args.size() arguments. - Args = llvm::makeArrayRef(TheCall->getArgs(), Args.size()); + Args = llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()); + + // A new call expression node was created if some typos were corrected. + // However it may not have been constructed with enough storage. In this + // case, rebuild the node with enough storage. The waste of space is + // immaterial since this only happens when some typos were corrected. + if (CorrectedTypos && Args.size() < NumParams) { + if (Config) + TheCall = CUDAKernelCallExpr::Create( + Context, Fn, cast<CallExpr>(Config), Args, ResultTy, VK_RValue, + RParenLoc, NumParams); + else + TheCall = CallExpr::Create(Context, Fn, Args, ResultTy, VK_RValue, + RParenLoc, NumParams, UsesADL); + } + // We can now handle the nulled arguments for the default arguments. + TheCall->setNumArgsUnsafe(std::max<unsigned>(Args.size(), NumParams)); } // Bail out early if calling a builtin with custom type checking. diff --git a/test/Sema/typo-correction.c b/test/Sema/typo-correction.c index e7992ac90b..73ba265509 100644 --- a/test/Sema/typo-correction.c +++ b/test/Sema/typo-correction.c @@ -100,3 +100,18 @@ void rdar38642201_caller() { structVar1.fieldName1.member1, //expected-error{{use of undeclared identifier 'structVar1'}} structVar2.fieldName2.member2); //expected-error{{use of undeclared identifier 'structVar2'}} } + +void PR40286_g(int x, int y); +void PR40286_h(int x, int y, int z); +void PR40286_1(int the_value) { + PR40286_g(the_walue); // expected-error {{use of undeclared identifier 'the_walue'}} +} +void PR40286_2(int the_value) { + PR40286_h(the_value, the_walue); // expected-error {{use of undeclared identifier 'the_walue'}} +} +void PR40286_3(int the_value) { + PR40286_h(the_walue); // expected-error {{use of undeclared identifier 'the_walue'}} +} +void PR40286_4(int the_value) { // expected-note {{'the_value' declared here}} + PR40286_h(the_value, the_value, the_walue); // expected-error {{use of undeclared identifier 'the_walue'; did you mean 'the_value'?}} +} |