]> granicus.if.org Git - clang/commitdiff
Sema: Use the right type for PredefinedExpr when it's in a lambda.
authorBenjamin Kramer <benny.kra@googlemail.com>
Wed, 21 Aug 2013 11:45:27 +0000 (11:45 +0000)
committerBenjamin Kramer <benny.kra@googlemail.com>
Wed, 21 Aug 2013 11:45:27 +0000 (11:45 +0000)
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.

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

lib/AST/Expr.cpp
lib/CodeGen/CGExpr.cpp
lib/Sema/SemaExpr.cpp
test/SemaCXX/predefined-expr.cpp [new file with mode: 0644]

index 6a1e500d330aac2a3fc3c7b94de1a8dac7fd81a2..c2bbda334338ab0e6b4bea861c50b1eda59935e0 100644 (file)
@@ -585,7 +585,18 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
 
     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;
index 0e2085d80f486a11bae310b49d4daf7a6a3c9b73..f5ca2d09740db85f0c4f939aba1554b9445b2720 100644 (file)
@@ -1937,7 +1937,7 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
   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::EmitPredefinedLValue(const PredefinedExpr *E) {
       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;
index d0fb643eb354765254e7336111b320cc32985501..2dbc82dc7a537dd5c84c2221f811d3f2decff12d 100644 (file)
@@ -2759,14 +2759,14 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
   // 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);
diff --git a/test/SemaCXX/predefined-expr.cpp b/test/SemaCXX/predefined-expr.cpp
new file mode 100644 (file)
index 0000000..dc1c52f
--- /dev/null
@@ -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");
+  }
+  ();
+}