summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/AST/Expr.cpp13
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp23
-rw-r--r--clang/lib/Sema/SemaExpr.cpp16
-rw-r--r--clang/test/SemaCXX/predefined-expr.cpp40
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");
+ }
+ ();
+}
OpenPOWER on IntegriCloud