r188900 - Sema: Use the right type for PredefinedExpr when it's in a lambda.

Benjamin Kramer benny.kra at googlemail.com
Wed Aug 21 04:45:27 PDT 2013


Author: d0k
Date: Wed Aug 21 06:45:27 2013
New Revision: 188900

URL: http://llvm.org/viewvc/llvm-project?rev=188900&view=rev
Log:
Sema: Use the right type for PredefinedExpr when it's in a lambda.

1. We now print the return type of lambdas and return type deduced functions
as "auto". Trailing return types with decltype print the underlying type.
2. Use the lambda or block scope for the PredefinedExpr type instead of the
parent function. This fixes PR16946, a strange mismatch between type of the
expression and the actual result.
3. Verify the type in CodeGen.
4. The type for blocks is still wrong. They are numbered and the name is not
known until CodeGen.

Added:
    cfe/trunk/test/SemaCXX/predefined-expr.cpp
Modified:
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=188900&r1=188899&r2=188900&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Wed Aug 21 06:45:27 2013
@@ -585,7 +585,18 @@ std::string PredefinedExpr::ComputeName(
 
     POut.flush();
 
-    if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
+    // Print "auto" for all deduced return types. This includes C++1y return
+    // type deduction and lambdas. For trailing return types resolve the
+    // decltype expression. Otherwise print the real type when this is
+    // not a constructor or destructor.
+    if ((isa<CXXMethodDecl>(FD) &&
+         cast<CXXMethodDecl>(FD)->getParent()->isLambda()) ||
+        (FT && FT->getResultType()->getAs<AutoType>()))
+      Proto = "auto " + Proto;
+    else if (FT && FT->getResultType()->getAs<DecltypeType>())
+      FT->getResultType()->getAs<DecltypeType>()->getUnderlyingType()
+          .getAsStringInternal(Proto, Policy);
+    else if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
       AFT->getResultType().getAsStringInternal(Proto, Policy);
 
     Out << Proto;

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=188900&r1=188899&r2=188900&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Wed Aug 21 06:45:27 2013
@@ -1937,7 +1937,7 @@ LValue CodeGenFunction::EmitPredefinedLV
   case PredefinedExpr::Function:
   case PredefinedExpr::LFunction:
   case PredefinedExpr::PrettyFunction: {
-    unsigned IdentType = E->getIdentType();
+    PredefinedExpr::IdentType IdentType = E->getIdentType();
     std::string GlobalVarName;
 
     switch (IdentType) {
@@ -1961,17 +1961,24 @@ LValue CodeGenFunction::EmitPredefinedLV
       FnName = FnName.substr(1);
     GlobalVarName += FnName;
 
+    // If this is outside of a function use the top level decl.
     const Decl *CurDecl = CurCodeDecl;
-    if (CurDecl == 0)
+    if (CurDecl == 0 || isa<VarDecl>(CurDecl))
       CurDecl = getContext().getTranslationUnitDecl();
 
-    std::string FunctionName =
-        (isa<BlockDecl>(CurDecl)
-         ? FnName.str()
-         : PredefinedExpr::ComputeName((PredefinedExpr::IdentType)IdentType,
-                                       CurDecl));
+    const Type *ElemType = E->getType()->getArrayElementTypeNoTypeQual();
+    std::string FunctionName;
+    if (isa<BlockDecl>(CurDecl)) {
+      // Blocks use the mangled function name.
+      // FIXME: ComputeName should handle blocks.
+      FunctionName = FnName.str();
+    } else {
+      FunctionName = PredefinedExpr::ComputeName(IdentType, CurDecl);
+      assert(cast<ConstantArrayType>(E->getType())->getSize() - 1 ==
+                 FunctionName.size() &&
+             "Computed __func__ length differs from type!");
+    }
 
-    const Type* ElemType = E->getType()->getArrayElementTypeNoTypeQual();
     llvm::Constant *C;
     if (ElemType->isWideCharType()) {
       SmallString<32> RawChars;

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=188900&r1=188899&r2=188900&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Aug 21 06:45:27 2013
@@ -2759,14 +2759,14 @@ ExprResult Sema::ActOnPredefinedExpr(Sou
   // Pre-defined identifiers are of type char[x], where x is the length of the
   // string.
 
-  Decl *currentDecl = getCurFunctionOrMethodDecl();
-  // Blocks and lambdas can occur at global scope. Don't emit a warning.
-  if (!currentDecl) {
-    if (const BlockScopeInfo *BSI = getCurBlock())
-      currentDecl = BSI->TheDecl;
-    else if (const LambdaScopeInfo *LSI = getCurLambda())
-      currentDecl = LSI->CallOperator;
-  }
+  // Pick the current block, lambda or function.
+  Decl *currentDecl;
+  if (const BlockScopeInfo *BSI = getCurBlock())
+    currentDecl = BSI->TheDecl;
+  else if (const LambdaScopeInfo *LSI = getCurLambda())
+    currentDecl = LSI->CallOperator;
+  else
+    currentDecl = getCurFunctionOrMethodDecl();
 
   if (!currentDecl) {
     Diag(Loc, diag::ext_predef_outside_function);

Added: cfe/trunk/test/SemaCXX/predefined-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/predefined-expr.cpp?rev=188900&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/predefined-expr.cpp (added)
+++ cfe/trunk/test/SemaCXX/predefined-expr.cpp Wed Aug 21 06:45:27 2013
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -std=c++1y -fblocks -fsyntax-only -verify %s
+// PR16946
+// expected-no-diagnostics
+
+auto foo() {
+  static_assert(sizeof(__func__) == 4, "foo");
+  static_assert(sizeof(__FUNCTION__) == 4, "foo");
+  static_assert(sizeof(__PRETTY_FUNCTION__) == 11, "auto foo()");
+  return 0;
+}
+
+auto bar() -> decltype(42) {
+  static_assert(sizeof(__func__) == 4, "bar");
+  static_assert(sizeof(__FUNCTION__) == 4, "bar");
+  static_assert(sizeof(__PRETTY_FUNCTION__) == 10, "int bar()");
+  return 0;
+}
+
+int main() {
+  static_assert(sizeof(__func__) == 5, "main");
+  static_assert(sizeof(__FUNCTION__) == 5, "main");
+  static_assert(sizeof(__PRETTY_FUNCTION__) == 11, "int main()");
+
+  []() {
+    static_assert(sizeof(__func__) == 11, "operator()");
+    static_assert(sizeof(__FUNCTION__) == 11, "operator()");
+    static_assert(sizeof(__PRETTY_FUNCTION__) == 51,
+                  "auto main()::<anonymous class>::operator()() const");
+    return 0;
+  }
+  ();
+
+  ^{
+    // FIXME: This is obviously wrong.
+    static_assert(sizeof(__func__) == 1, "__main_block_invoke");
+    static_assert(sizeof(__FUNCTION__) == 1, "__main_block_invoke");
+    static_assert(sizeof(__PRETTY_FUNCTION__) == 1, "__main_block_invoke");
+  }
+  ();
+}





More information about the cfe-commits mailing list