diff options
| -rw-r--r-- | clang/lib/AST/Expr.cpp | 13 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 23 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 16 | ||||
| -rw-r--r-- | clang/test/SemaCXX/predefined-expr.cpp | 40 |
4 files changed, 75 insertions, 17 deletions
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 6a1e500d330..c2bbda33433 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -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; diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 0e2085d80f4..f5ca2d09740 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -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; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d0fb643eb35..2dbc82dc7a5 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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/clang/test/SemaCXX/predefined-expr.cpp b/clang/test/SemaCXX/predefined-expr.cpp new file mode 100644 index 00000000000..dc1c52fa4ba --- /dev/null +++ b/clang/test/SemaCXX/predefined-expr.cpp @@ -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"); + } + (); +} |

