From: Richard Smith Date: Tue, 27 Dec 2011 12:18:28 +0000 (+0000) Subject: constexpr: support for evaluation and codegen of typeid constants. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=47d2145675099893d702be4bc06bd9f26d8ddd13;p=clang constexpr: support for evaluation and codegen of typeid constants. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147290 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index d4e5693ff9..df0a50823d 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -33,6 +33,9 @@ def note_constexpr_past_end : Note< "%select{temporary|%2}1 is not a constant expression">; def note_constexpr_var_init_non_constant : Note< "initializer of %0 is not a constant expression">; +def note_constexpr_typeid_polymorphic : Note< + "typeid applied to expression of polymorphic type %0 is " + "not allowed in a constant expression">; def note_constexpr_temporary_here : Note<"temporary created here">; def note_constexpr_literal_here : Note<"literal written here">; def note_constexpr_depth_limit_exceeded : Note< diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 4fc75a613e..46580697de 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -697,6 +697,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) { case Expr::PredefinedExprClass: case Expr::ObjCStringLiteralClass: case Expr::ObjCEncodeExprClass: + case Expr::CXXTypeidExprClass: return true; case Expr::CallExprClass: return IsStringLiteralCall(cast(E)); @@ -2329,6 +2330,7 @@ public: // - Literals // * CompoundLiteralExpr in C // * StringLiteral +// * CXXTypeidExpr // * PredefinedExpr // * ObjCStringLiteralExpr // * ObjCEncodeExpr @@ -2356,6 +2358,7 @@ public: bool VisitMemberExpr(const MemberExpr *E); bool VisitStringLiteral(const StringLiteral *E) { return Success(E); } bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { return Success(E); } + bool VisitCXXTypeidExpr(const CXXTypeidExpr *E); bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E); bool VisitUnaryDeref(const UnaryOperator *E); @@ -2451,6 +2454,19 @@ LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { return Success(E); } +bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { + if (E->isTypeOperand()) + return Success(E); + CXXRecordDecl *RD = E->getExprOperand()->getType()->getAsCXXRecordDecl(); + if (RD && RD->isPolymorphic()) { + Info.Diag(E->getExprLoc(), diag::note_constexpr_typeid_polymorphic) + << E->getExprOperand()->getType() + << E->getExprOperand()->getSourceRange(); + return false; + } + return Success(E); +} + bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { // Handle static data members. if (const VarDecl *VD = dyn_cast(E->getMemberDecl())) { diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 136b713910..1bd94295d3 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -934,6 +934,15 @@ public: return CGM.GetAddrOfGlobalBlock(cast(E), FunctionName.c_str()); } + case Expr::CXXTypeidExprClass: { + CXXTypeidExpr *Typeid = cast(E); + QualType T; + if (Typeid->isTypeOperand()) + T = Typeid->getTypeOperand(); + else + T = Typeid->getExprOperand()->getType(); + return CGM.GetAddrOfRTTIDescriptor(T); + } } return 0; diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp index 727f441dab..f0581fcc09 100644 --- a/test/CXX/expr/expr.const/p2-0x.cpp +++ b/test/CXX/expr/expr.const/p2-0x.cpp @@ -280,11 +280,10 @@ namespace std { namespace TypeId { struct S { virtual void f(); }; constexpr S *p = 0; - constexpr const std::type_info &ti1 = typeid(*p); // expected-error {{must be initialized by a constant expression}} + constexpr const std::type_info &ti1 = typeid(*p); // expected-error {{must be initialized by a constant expression}} expected-note {{typeid applied to expression of polymorphic type 'TypeId::S'}} - // FIXME: Implement typeid evaluation. struct T {} t; - constexpr const std::type_info &ti2 = typeid(t); // unexpected-error {{must be initialized by a constant expression}} + constexpr const std::type_info &ti2 = typeid(t); } // - a new-expression (5.3.4); diff --git a/test/CodeGenCXX/typeid-cxx11.cpp b/test/CodeGenCXX/typeid-cxx11.cpp new file mode 100644 index 0000000000..940274e965 --- /dev/null +++ b/test/CodeGenCXX/typeid-cxx11.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -std=c++11 -o - | FileCheck %s +#include + +namespace Test1 { + +struct Item { + const std::type_info &ti; + const char *name; + void *(*make)(); +}; + +template void *make_impl() { return new T; } +template constexpr Item item(const char *name) { + return { typeid(T), name, make_impl }; +} + +struct A { virtual ~A(); }; +struct B : virtual A {}; +struct C { int n; }; + +// FIXME: check we produce a constant array for this, once we support IRGen of +// folded structs and arrays. +constexpr Item items[] = { + item("A"), item("B"), item("C"), item("int") +}; + +// CHECK: @_ZN5Test11xE = constant %"class.std::type_info"* bitcast (i8** @_ZTIN5Test11AE to %"class.std::type_info"*), align 8 +constexpr auto &x = items[0].ti; + +} diff --git a/test/CodeGenCXX/typeid.cpp b/test/CodeGenCXX/typeid.cpp index 7ebf41c09f..fce3795344 100644 --- a/test/CodeGenCXX/typeid.cpp +++ b/test/CodeGenCXX/typeid.cpp @@ -6,6 +6,27 @@ namespace Test1 { // PR7400 struct A { virtual void f(); }; +// CHECK: @_ZN5Test16int_tiE = constant %"class.std::type_info"* bitcast (i8** @_ZTIi to %"class.std::type_info"*), align 8 +const std::type_info &int_ti = typeid(int); + +// CHECK: @_ZN5Test14A_tiE = constant %"class.std::type_info"* bitcast (i8** @_ZTIN5Test11AE to %"class.std::type_info"*), align 8 +const std::type_info &A_ti = typeid(const volatile A &); + +volatile char c; + +// CHECK: @_ZN5Test14c_tiE = constant %"class.std::type_info"* bitcast (i8** @_ZTIc to %"class.std::type_info"*), align 8 +const std::type_info &c_ti = typeid(c); + +extern const double &d; + +// CHECK: @_ZN5Test14d_tiE = constant %"class.std::type_info"* bitcast (i8** @_ZTId to %"class.std::type_info"*), align 8 +const std::type_info &d_ti = typeid(d); + +extern A &a; + +// CHECK: @_ZN5Test14a_tiE = global +const std::type_info &a_ti = typeid(a); + // CHECK: define i8* @_ZN5Test11fEv const char *f() { try {