llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Henrik G. Olsson (hnrklssn)

<details>
<summary>Changes</summary>

When transforming a block expression we would transform the return type, but 
ignore the return type location. When using the `typename` keyword this would 
result in an elaborated type with invalid source location,
which would trigger the `(Keyword != ElaboratedTypeKeyword::None) == 
KeywordLoc.isValid()` assertion in `CheckTypenameType`.

rdar://184773464

---
Full diff: https://github.com/llvm/llvm-project/pull/226431.diff


2 Files Affected:

- (modified) clang/lib/Sema/TreeTransform.h (+25-2) 
- (modified) clang/test/SemaObjCXX/blocks.mm (+37-2) 


``````````diff
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index e482d15f31cc5f..b9115da43bed21 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -17910,8 +17910,31 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr 
*E) {
     return ExprError();
   }
 
-  QualType exprResultType =
-      getDerived().TransformType(exprFunctionType->getReturnType());
+  TypeLoc resultTL;
+  if (TypeSourceInfo *SigTSI = oldBlock->getSignatureAsWritten()) {
+    resultTL = SigTSI->getTypeLoc();
+    // If there's no FunctionProtoTypeLoc, the typeloc is just the return type.
+    if (auto FTL = resultTL.getAsAdjusted<FunctionProtoTypeLoc>())
+      resultTL = FTL.getReturnLoc();
+  }
+  QualType exprResultType;
+  if (resultTL && resultTL.getType() == exprFunctionType->getReturnType()) {
+    // Preserve the source location for any elaborated-type keywords
+    // (e.g. 'typename')
+    TypeSourceInfo *ResultTSI = SemaRef.Context.CreateTypeSourceInfo(
+        resultTL.getType(), resultTL.getFullDataSize());
+    ResultTSI->getTypeLoc().initializeFullCopy(resultTL);
+    if (TypeSourceInfo *NewResultTSI = getDerived().TransformType(ResultTSI))
+      exprResultType = NewResultTSI->getType();
+  } else {
+    // Fallback for deduced return types, since they lack a source location.
+    exprResultType =
+        getDerived().TransformType(exprFunctionType->getReturnType());
+  }
+  if (exprResultType.isNull()) {
+    getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/nullptr);
+    return ExprError();
+  }
 
   auto epi = exprFunctionType->getExtProtoInfo();
   epi.ExtParameterInfos = extParamInfos.getPointerOrNull(paramTypes.size());
diff --git a/clang/test/SemaObjCXX/blocks.mm b/clang/test/SemaObjCXX/blocks.mm
index f1b5b301087eb5..c74a3e0ff8f375 100644
--- a/clang/test/SemaObjCXX/blocks.mm
+++ b/clang/test/SemaObjCXX/blocks.mm
@@ -33,7 +33,7 @@ - (void)bar;
 @end
 
 namespace N {
-  class X { };      
+  class X { };
   void foo(X);
 }
 
@@ -45,7 +45,7 @@ - (void)bar {
 @end
 
 typedef signed char BOOL;
-void foo6(void *block) {  
+void foo6(void *block) {
        void (^vb)(id obj, int idx, BOOL *stop) = (void (^)(id, int, BOOL 
*))block;
     BOOL (^bb)(id obj, int idx, BOOL *stop) = (BOOL (^)(id, int, BOOL *))block;
 }
@@ -147,6 +147,41 @@ void f(T t) {
   template void f<X>(X);
 }
 
+namespace DependentTypenameReturnType {
+  // Success case
+  template <class T> struct S { typedef int type; };
+  template <class T> void f() {
+    auto b = ^ typename S<T>::type () { return 0; };
+    (void)b;
+  }
+  template void f<int>();
+
+  // Same as 'f' but with no parameter list. The written block signature is
+  // then stored as just the return-type loc (there is no FunctionProtoTypeLoc
+  // to look through).
+  template <class T> void g() {
+    auto b = ^ typename S<T>::type { return 0; };
+    (void)b;
+  }
+  template void g<int>();
+
+  // A block with no explicit return type has no return-type source location, 
so
+  // it takes the deduced-return fallback in TransformBlockExpr.
+  template <class T> T h() {
+    auto b = ^ { T x{}; return x; };
+    return b();
+  }
+  template int h<int>();
+
+  // Failure case
+  template <class T> struct NoType {};
+  template <class T> void i() {
+    auto b = ^ typename NoType<T>::type () { return 0; }; // 
expected-error{{no type named 'type' in 
'DependentTypenameReturnType::NoType<int>'}}
+    (void)b;
+  }
+  template void i<int>(); // expected-note{{in instantiation of function 
template specialization 'DependentTypenameReturnType::i<int>' requested here}}
+}
+
 namespace GenericLambdaCapture {
 int test(int outerp) {
   auto lambda =[&](auto p) {

``````````

</details>


https://github.com/llvm/llvm-project/pull/226431
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to