aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/APValue.h91
-rw-r--r--clang/include/clang/Basic/DiagnosticASTKinds.td3
-rw-r--r--clang/lib/AST/APValue.cpp59
-rw-r--r--clang/lib/AST/ExprConstant.cpp47
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp11
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp9
-rw-r--r--clang/test/CXX/drs/dr19xx.cpp9
-rw-r--r--clang/test/Parser/MicrosoftExtensions.cpp2
-rw-r--r--clang/test/SemaCXX/builtin-constant-p.cpp5
-rw-r--r--clang/test/SemaCXX/typeid.cpp5
-rwxr-xr-xclang/www/cxx_dr_status.html2
11 files changed, 196 insertions, 47 deletions
diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h
index d266473..a6b0fc5 100644
--- a/clang/include/clang/AST/APValue.h
+++ b/clang/include/clang/AST/APValue.h
@@ -24,14 +24,52 @@ namespace clang {
class AddrLabelExpr;
class ASTContext;
class CharUnits;
+ class CXXRecordDecl;
+ class Decl;
class DiagnosticBuilder;
class Expr;
class FieldDecl;
- class Decl;
+ struct PrintingPolicy;
+ class Type;
class ValueDecl;
- class CXXRecordDecl;
- class QualType;
+/// Symbolic representation of typeid(T) for some type T.
+class TypeInfoLValue {
+ const Type *T;
+
+public:
+ TypeInfoLValue() : T() {}
+ explicit TypeInfoLValue(const Type *T);
+
+ const Type *getType() const { return T; }
+ explicit operator bool() const { return T; }
+
+ void *getOpaqueValue() { return const_cast<Type*>(T); }
+ static TypeInfoLValue getFromOpaqueValue(void *Value) {
+ TypeInfoLValue V;
+ V.T = reinterpret_cast<const Type*>(Value);
+ return V;
+ }
+
+ void print(llvm::raw_ostream &Out, const PrintingPolicy &Policy) const;
+};
+}
+
+namespace llvm {
+template<> struct PointerLikeTypeTraits<clang::TypeInfoLValue> {
+ static void *getAsVoidPointer(clang::TypeInfoLValue V) {
+ return V.getOpaqueValue();
+ }
+ static clang::TypeInfoLValue getFromVoidPointer(void *P) {
+ return clang::TypeInfoLValue::getFromOpaqueValue(P);
+ }
+ // Validated by static_assert in APValue.cpp; hardcoded to avoid needing
+ // to include Type.h.
+ static constexpr int NumLowBitsAvailable = 3;
+};
+}
+
+namespace clang {
/// APValue - This class implements a discriminated union of [uninitialized]
/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset],
/// [Vector: N * APValue], [Array: N * APValue]
@@ -57,13 +95,18 @@ public:
class LValueBase {
public:
- typedef llvm::PointerUnion<const ValueDecl *, const Expr *> PtrTy;
+ typedef llvm::PointerUnion<const ValueDecl *, const Expr *, TypeInfoLValue>
+ PtrTy;
- LValueBase() : CallIndex(0), Version(0) {}
+ LValueBase() : Local{} {}
template <class T>
- LValueBase(T P, unsigned I = 0, unsigned V = 0)
- : Ptr(P), CallIndex(I), Version(V) {}
+ LValueBase(T P, unsigned I = 0, unsigned V = 0) : Ptr(P), Local{I, V} {
+ assert(!is<TypeInfoLValue>() &&
+ "don't use this constructor to form a type_info lvalue");
+ }
+
+ static LValueBase getTypeInfo(TypeInfoLValue LV, QualType TypeInfo);
template <class T>
bool is() const { return Ptr.is<T>(); }
@@ -78,28 +121,15 @@ public:
bool isNull() const;
- explicit operator bool () const;
+ explicit operator bool() const;
- PtrTy getPointer() const {
- return Ptr;
- }
-
- unsigned getCallIndex() const {
- return CallIndex;
- }
+ PtrTy getPointer() const { return Ptr; }
- void setCallIndex(unsigned Index) {
- CallIndex = Index;
- }
+ unsigned getCallIndex() const;
+ unsigned getVersion() const;
+ QualType getTypeInfoType() const;
- unsigned getVersion() const {
- return Version;
- }
-
- friend bool operator==(const LValueBase &LHS, const LValueBase &RHS) {
- return LHS.Ptr == RHS.Ptr && LHS.CallIndex == RHS.CallIndex &&
- LHS.Version == RHS.Version;
- }
+ friend bool operator==(const LValueBase &LHS, const LValueBase &RHS);
friend bool operator!=(const LValueBase &LHS, const LValueBase &RHS) {
return !(LHS == RHS);
}
@@ -107,7 +137,14 @@ public:
private:
PtrTy Ptr;
- unsigned CallIndex, Version;
+ struct LocalState {
+ unsigned CallIndex, Version;
+ };
+ union {
+ LocalState Local;
+ /// The type std::type_info, if this is a TypeInfoLValue.
+ void *TypeInfoType;
+ };
};
/// A FieldDecl or CXXRecordDecl, along with a flag indicating whether we
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index 17256fb..3e9ebbb 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -160,6 +160,9 @@ def note_constexpr_access_static_temporary : Note<
"dynamic_cast of}0 temporary "
"is not allowed in a constant expression outside the expression that "
"created the temporary">;
+def note_constexpr_access_unreadable_object : Note<
+ "%select{read of|assignment to|increment of|decrement of|member call on|"
+ "dynamic_cast of}0 object '%1' whose value is not known">;
def note_constexpr_modify_global : Note<
"a constant expression cannot modify an object that is visible outside "
"that expression">;
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp
index e7902e68..83b0fb5 100644
--- a/clang/lib/AST/APValue.cpp
+++ b/clang/lib/AST/APValue.cpp
@@ -20,6 +20,56 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+/// The identity of a type_info object depends on the canonical unqualified
+/// type only.
+TypeInfoLValue::TypeInfoLValue(const Type *T)
+ : T(T->getCanonicalTypeUnqualified().getTypePtr()) {}
+
+void TypeInfoLValue::print(llvm::raw_ostream &Out,
+ const PrintingPolicy &Policy) const {
+ Out << "typeid(";
+ QualType(getType(), 0).print(Out, Policy);
+ Out << ")";
+}
+
+static_assert(
+ 1 << llvm::PointerLikeTypeTraits<TypeInfoLValue>::NumLowBitsAvailable <=
+ alignof(const Type *),
+ "Type is insufficiently aligned");
+
+APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV,
+ QualType TypeInfo) {
+ LValueBase Base;
+ Base.Ptr = LV;
+ Base.TypeInfoType = TypeInfo.getAsOpaquePtr();
+ return Base;
+}
+
+unsigned APValue::LValueBase::getCallIndex() const {
+ return is<TypeInfoLValue>() ? 0 : Local.CallIndex;
+}
+
+unsigned APValue::LValueBase::getVersion() const {
+ return is<TypeInfoLValue>() ? 0 : Local.Version;
+}
+
+QualType APValue::LValueBase::getTypeInfoType() const {
+ assert(is<TypeInfoLValue>() && "not a type_info lvalue");
+ return QualType::getFromOpaquePtr(TypeInfoType);
+}
+
+namespace clang {
+bool operator==(const APValue::LValueBase &LHS,
+ const APValue::LValueBase &RHS) {
+ if (LHS.Ptr != RHS.Ptr)
+ return false;
+ if (LHS.is<TypeInfoLValue>())
+ return true;
+ return LHS.Local.CallIndex == RHS.Local.CallIndex &&
+ LHS.Local.Version == RHS.Local.Version;
+}
+}
+
namespace {
struct LVBase {
APValue::LValueBase Base;
@@ -60,6 +110,8 @@ llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() {
namespace clang {
llvm::hash_code hash_value(const APValue::LValueBase &Base) {
+ if (Base.is<TypeInfoLValue>())
+ return llvm::hash_value(Base.getOpaqueValue());
return llvm::hash_combine(Base.getOpaqueValue(), Base.getCallIndex(),
Base.getVersion());
}
@@ -470,7 +522,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
Out << *VD;
- else {
+ else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
+ TI.print(Out, Ctx.getPrintingPolicy());
+ } else {
assert(Base.get<const Expr *>() != nullptr &&
"Expecting non-null Expr");
Base.get<const Expr*>()->printPretty(Out, nullptr,
@@ -495,6 +549,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
Out << *VD;
ElemTy = VD->getType();
+ } else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
+ TI.print(Out, Ctx.getPrintingPolicy());
+ ElemTy = Base.getTypeInfoType();
} else {
const Expr *E = Base.get<const Expr*>();
assert(E != nullptr && "Expecting non-null Expr");
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 29b6d12..e41264e 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -87,6 +87,9 @@ namespace {
return D->getType();
}
+ if (TypeInfoLValue TI = B.dyn_cast<TypeInfoLValue>())
+ return B.getTypeInfoType();
+
const Expr *Base = B.get<const Expr*>();
// For a materialized temporary, the type of the temporary we materialized
@@ -1783,6 +1786,9 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
return isa<FunctionDecl>(D);
}
+ if (B.is<TypeInfoLValue>())
+ return true;
+
const Expr *E = B.get<const Expr*>();
switch (E->getStmtClass()) {
default:
@@ -1800,7 +1806,6 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
case Expr::PredefinedExprClass:
case Expr::ObjCStringLiteralClass:
case Expr::ObjCEncodeExprClass:
- case Expr::CXXTypeidExprClass:
case Expr::CXXUuidofExprClass:
return true;
case Expr::ObjCBoxedExprClass:
@@ -1878,9 +1883,9 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
if (VD)
Info.Note(VD->getLocation(), diag::note_declared_at);
- else
- Info.Note(Base.get<const Expr*>()->getExprLoc(),
- diag::note_constexpr_temporary_here);
+ else if (const Expr *E = Base.dyn_cast<const Expr*>())
+ Info.Note(E->getExprLoc(), diag::note_constexpr_temporary_here);
+ // We have no information to show for a typeid(T) object.
}
/// Check that this reference or pointer core constant expression is a valid
@@ -3404,7 +3409,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
if (!Frame) {
if (const MaterializeTemporaryExpr *MTE =
- dyn_cast<MaterializeTemporaryExpr>(Base)) {
+ dyn_cast_or_null<MaterializeTemporaryExpr>(Base)) {
assert(MTE->getStorageDuration() == SD_Static &&
"should have a frame for a non-global materialized temporary");
@@ -3439,7 +3444,13 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
} else {
if (!IsAccess)
return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
- Info.FFDiag(E);
+ APValue Val;
+ LVal.moveInto(Val);
+ Info.FFDiag(E, diag::note_constexpr_access_unreadable_object)
+ << AK
+ << Val.getAsString(Info.Ctx,
+ Info.Ctx.getLValueReferenceType(LValType));
+ NoteLValueLocation(Info, LVal.Base);
return CompleteObject();
}
} else {
@@ -5777,13 +5788,13 @@ public:
// - Literals
// * CompoundLiteralExpr in C (and in global scope in C++)
// * StringLiteral
-// * CXXTypeidExpr
// * PredefinedExpr
// * ObjCStringLiteralExpr
// * ObjCEncodeExpr
// * AddrLabelExpr
// * BlockExpr
// * CallExpr for a MakeStringConstant builtin
+// - typeid(T) expressions, as TypeInfoLValues
// - Locals and temporaries
// * MaterializeTemporaryExpr
// * Any Expr, with a CallIndex indicating the function in which the temporary
@@ -6018,8 +6029,14 @@ LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
}
bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
- if (!E->isPotentiallyEvaluated())
- return Success(E);
+ if (!E->isPotentiallyEvaluated()) {
+ TypeInfoLValue TypeInfo;
+ if (E->isTypeOperand())
+ TypeInfo = TypeInfoLValue(E->getTypeOperand(Info.Ctx).getTypePtr());
+ else
+ TypeInfo = TypeInfoLValue(E->getExprOperand()->getType().getTypePtr());
+ return Success(APValue::LValueBase::getTypeInfo(TypeInfo, E->getType()));
+ }
Info.FFDiag(E, diag::note_constexpr_typeid_polymorphic)
<< E->getExprOperand()->getType()
@@ -6615,9 +6632,11 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
if (const ValueDecl *VD =
OffsetResult.Base.dyn_cast<const ValueDecl*>()) {
BaseAlignment = Info.Ctx.getDeclAlign(VD);
+ } else if (const Expr *E = OffsetResult.Base.dyn_cast<const Expr *>()) {
+ BaseAlignment = GetAlignOfExpr(Info, E, UETT_AlignOf);
} else {
- BaseAlignment = GetAlignOfExpr(
- Info, OffsetResult.Base.get<const Expr *>(), UETT_AlignOf);
+ BaseAlignment = GetAlignOfType(
+ Info, OffsetResult.Base.getTypeInfoType(), UETT_AlignOf);
}
if (BaseAlignment < Align) {
@@ -8335,6 +8354,10 @@ static bool EvaluateBuiltinConstantPForLValue(const APValue &LV) {
if (!isa<StringLiteral>(E))
return false;
return LV.getLValueOffset().isZero();
+ } else if (Base.is<TypeInfoLValue>()) {
+ // Surprisingly, GCC considers __builtin_constant_p(&typeid(int)) to
+ // evaluate to true.
+ return true;
} else {
// Any other base is not constant enough for GCC.
return false;
@@ -8399,6 +8422,8 @@ static QualType getObjectType(APValue::LValueBase B) {
} else if (const Expr *E = B.get<const Expr*>()) {
if (isa<CompoundLiteralExpr>(E))
return E->getType();
+ } else if (B.is<TypeInfoLValue>()) {
+ return B.getTypeInfoType();
}
return QualType();
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index dd71cf0..70904b1 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1735,6 +1735,17 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
return nullptr;
}
+ // Handle typeid(T).
+ if (TypeInfoLValue TI = base.dyn_cast<TypeInfoLValue>()) {
+ llvm::Type *StdTypeInfoPtrTy =
+ CGM.getTypes().ConvertType(base.getTypeInfoType())->getPointerTo();
+ llvm::Constant *TypeInfo =
+ CGM.GetAddrOfRTTIDescriptor(QualType(TI.getType(), 0));
+ if (TypeInfo->getType() != StdTypeInfoPtrTy)
+ TypeInfo = llvm::ConstantExpr::getBitCast(TypeInfo, StdTypeInfoPtrTy);
+ return TypeInfo;
+ }
+
// Otherwise, it must be an expression.
return Visit(base.get<const Expr*>());
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index b9d3ff8..239b4ae 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -6424,8 +6424,11 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// -- a string literal
// -- the result of a typeid expression, or
// -- a predefined __func__ variable
- if (auto *E = Value.getLValueBase().dyn_cast<const Expr*>()) {
- if (isa<CXXUuidofExpr>(E)) {
+ APValue::LValueBase Base = Value.getLValueBase();
+ auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
+ if (Base && !VD) {
+ auto *E = Base.dyn_cast<const Expr *>();
+ if (E && isa<CXXUuidofExpr>(E)) {
Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts());
break;
}
@@ -6433,8 +6436,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
<< Arg->getSourceRange();
return ExprError();
}
- auto *VD = const_cast<ValueDecl *>(
- Value.getLValueBase().dyn_cast<const ValueDecl *>());
// -- a subobject
if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 &&
VD && VD->getType()->isArrayType() &&
diff --git a/clang/test/CXX/drs/dr19xx.cpp b/clang/test/CXX/drs/dr19xx.cpp
index a1e8c76..4e359681 100644
--- a/clang/test/CXX/drs/dr19xx.cpp
+++ b/clang/test/CXX/drs/dr19xx.cpp
@@ -167,9 +167,14 @@ namespace dr1959 { // dr1959: 3.9
#endif
}
-namespace dr1968 { // dr1968: yes
+namespace dr1968 { // dr1968: no
#if __cplusplus >= 201103L
- static_assert(&typeid(int) == &typeid(int), ""); // expected-error{{not an integral constant expression}}
+ // FIXME: According to DR1968, both of these should be considered
+ // non-constant.
+ static_assert(&typeid(int) == &typeid(int), "");
+
+ constexpr const std::type_info *f() { return &typeid(int); }
+ static_assert(f() == f(), "");
#endif
}
diff --git a/clang/test/Parser/MicrosoftExtensions.cpp b/clang/test/Parser/MicrosoftExtensions.cpp
index 63e8b60..913645b 100644
--- a/clang/test/Parser/MicrosoftExtensions.cpp
+++ b/clang/test/Parser/MicrosoftExtensions.cpp
@@ -138,6 +138,8 @@ typedef COM_CLASS_TEMPLATE_REF<struct_with_uuid, __uuidof(struct_with_uuid)> COM
COM_CLASS_TEMPLATE_REF<int, __uuidof(struct_with_uuid)> good_template_arg;
COM_CLASS_TEMPLATE<int, __uuidof(struct_with_uuid)> bad_template_arg; // expected-error {{non-type template argument of type 'const _GUID' is not a constant expression}}
+// expected-note@-1 {{read of object '__uuidof(struct_with_uuid)' whose value is not known}}
+// expected-note@-2 {{temporary created here}}
namespace PR16911 {
struct __declspec(uuid("{12345678-1234-1234-1234-1234567890aB}")) uuid;
diff --git a/clang/test/SemaCXX/builtin-constant-p.cpp b/clang/test/SemaCXX/builtin-constant-p.cpp
index 21cbaf7..f70676d 100644
--- a/clang/test/SemaCXX/builtin-constant-p.cpp
+++ b/clang/test/SemaCXX/builtin-constant-p.cpp
@@ -130,3 +130,8 @@ constexpr int mutate6(bool mutate) {
static_assert(mutate6(false) == 11);
// Mutation of state outside __builtin_constant_p: evaluates to false.
static_assert(mutate6(true) == 10);
+
+// GCC strangely returns true for the address of a type_info object, despite it
+// not being a pointer to the start of a string literal.
+namespace std { struct type_info; }
+static_assert(__builtin_constant_p(&typeid(int)));
diff --git a/clang/test/SemaCXX/typeid.cpp b/clang/test/SemaCXX/typeid.cpp
index 48fcce0..4e696de 100644
--- a/clang/test/SemaCXX/typeid.cpp
+++ b/clang/test/SemaCXX/typeid.cpp
@@ -6,7 +6,7 @@ void f()
}
namespace std {
- class type_info;
+ struct type_info { const char *name; };
}
void g()
@@ -27,3 +27,6 @@ void h(int i) {
typeid(V); // expected-error{{'typeid' of variably modified type 'char [i]'}}
typeid(char [i]); // expected-error{{'typeid' of variably modified type 'char [i]'}}
}
+
+// expected-note@+1 {{read of object 'typeid(int).name' whose value is not known}}
+constexpr const char *name = typeid(int).name; // expected-error {{constant expression}}
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 6592e83..663fe58 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -11623,7 +11623,7 @@ and <I>POD class</I></td>
<td><a href="http://wg21.link/cwg1968">1968</a></td>
<td>NAD</td>
<td>Address of <TT>typeid</TT> in constant expressions</td>
- <td class="full" align="center">Yes</td>
+ <td class="none" align="center">No</td>
</tr>
<tr class="open" id="1969">
<td><a href="http://wg21.link/cwg1969">1969</a></td>