]> granicus.if.org Git - clang/commitdiff
Merging r354035:
authorHans Wennborg <hans@hanshq.net>
Mon, 18 Feb 2019 09:31:05 +0000 (09:31 +0000)
committerHans Wennborg <hans@hanshq.net>
Mon, 18 Feb 2019 09:31:05 +0000 (09:31 +0000)
------------------------------------------------------------------------
r354035 | brunoricci | 2019-02-14 16:43:17 +0100 (Thu, 14 Feb 2019) | 23 lines

[Sema] Fix a regression introduced in "[AST][Sema] Remove CallExpr::setNumArgs"

D54902 removed CallExpr::setNumArgs in preparation of tail-allocating the
arguments of CallExpr. It did this by allocating storage for
max(number of arguments, number of parameters in the prototype). The
temporarily nulled arguments however causes issues in BuildResolvedCallExpr
when typo correction is done just after the creation of the call expression.

This was unfortunately missed by the tests /:

To fix this, delay setting the number of arguments to
max(number of arguments, number of parameters in the prototype) until we are
ready for it. It would be nice to have this encapsulated in CallExpr but this
is the best I can come up with under the constraint that we cannot add
anything the CallExpr.

Fixes PR40286.

Differential Revision: https://reviews.llvm.org/D57948

Reviewed By: aaron.ballman

------------------------------------------------------------------------

git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_80@354247 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Expr.h
lib/Sema/SemaExpr.cpp
test/Sema/typo-correction.c

index 3de73428829b3342545f22709eeb6d6836c10974..bf4f3babbd3c63754a91e2f7d3943361042ffec5 100644 (file)
@@ -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;
index db0c62630a9ec087ec74b916016e3f56770abc08..ff9393a56b9cba979137af579926f4c83676361b 100644 (file)
@@ -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.
index e7992ac90bb3d6e651f19a5c549bd2b35214e3a9..73ba265509e4ce4b34360e9be896a6af4de98770 100644 (file)
@@ -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'?}}
+}