Stop instantiating a class if we hit a static_assert failure. Also, if the

static_assert fails when parsing the template, don't diagnose it again on every
instantiation.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160088 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Smith 2012-07-11 22:37:56 +00:00
Родитель 18b7f95bdb
Коммит e3f470a718
9 изменённых файлов: 73 добавлений и 30 удалений

Просмотреть файл

@ -2892,31 +2892,33 @@ public:
/// \brief Represents a C++11 static_assert declaration.
class StaticAssertDecl : public Decl {
virtual void anchor();
Expr *AssertExpr;
llvm::PointerIntPair<Expr *, 1, bool> AssertExprAndFailed;
StringLiteral *Message;
SourceLocation RParenLoc;
StaticAssertDecl(DeclContext *DC, SourceLocation StaticAssertLoc,
Expr *assertexpr, StringLiteral *message,
SourceLocation RParenLoc)
: Decl(StaticAssert, DC, StaticAssertLoc), AssertExpr(assertexpr),
Message(message), RParenLoc(RParenLoc) { }
Expr *AssertExpr, StringLiteral *Message,
SourceLocation RParenLoc, bool Failed)
: Decl(StaticAssert, DC, StaticAssertLoc),
AssertExprAndFailed(AssertExpr, Failed), Message(Message),
RParenLoc(RParenLoc) { }
public:
static StaticAssertDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StaticAssertLoc,
Expr *AssertExpr, StringLiteral *Message,
SourceLocation RParenLoc);
SourceLocation RParenLoc, bool Failed);
static StaticAssertDecl *CreateDeserialized(ASTContext &C, unsigned ID);
Expr *getAssertExpr() { return AssertExpr; }
const Expr *getAssertExpr() const { return AssertExpr; }
Expr *getAssertExpr() { return AssertExprAndFailed.getPointer(); }
const Expr *getAssertExpr() const { return AssertExprAndFailed.getPointer(); }
StringLiteral *getMessage() { return Message; }
const StringLiteral *getMessage() const { return Message; }
bool isFailed() const { return AssertExprAndFailed.getInt(); }
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getLocation(), getRParenLoc());

Просмотреть файл

@ -4306,6 +4306,11 @@ public:
Expr *AssertExpr,
Expr *AssertMessageExpr,
SourceLocation RParenLoc);
Decl *BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Expr *AssertExpr,
StringLiteral *AssertMessageExpr,
SourceLocation RParenLoc,
bool Failed);
FriendDecl *CheckFriendTypeDecl(SourceLocation Loc,
SourceLocation FriendLoc,

Просмотреть файл

@ -2005,15 +2005,17 @@ StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StaticAssertLoc,
Expr *AssertExpr,
StringLiteral *Message,
SourceLocation RParenLoc) {
SourceLocation RParenLoc,
bool Failed) {
return new (C) StaticAssertDecl(DC, StaticAssertLoc, AssertExpr, Message,
RParenLoc);
RParenLoc, Failed);
}
StaticAssertDecl *StaticAssertDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(StaticAssertDecl));
return new (Mem) StaticAssertDecl(0, SourceLocation(), 0, 0,SourceLocation());
return new (Mem) StaticAssertDecl(0, SourceLocation(), 0, 0,
SourceLocation(), false);
}
static const char *getAccessName(AccessSpecifier AS) {

Просмотреть файл

@ -9736,37 +9736,49 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Expr *AssertExpr,
Expr *AssertMessageExpr_,
Expr *AssertMessageExpr,
SourceLocation RParenLoc) {
StringLiteral *AssertMessage = cast<StringLiteral>(AssertMessageExpr_);
StringLiteral *AssertMessage = cast<StringLiteral>(AssertMessageExpr);
if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent()) {
if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression))
return 0;
return BuildStaticAssertDeclaration(StaticAssertLoc, AssertExpr,
AssertMessage, RParenLoc, false);
}
Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Expr *AssertExpr,
StringLiteral *AssertMessage,
SourceLocation RParenLoc,
bool Failed) {
if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent() &&
!Failed) {
// In a static_assert-declaration, the constant-expression shall be a
// constant expression that can be contextually converted to bool.
ExprResult Converted = PerformContextuallyConvertToBool(AssertExpr);
if (Converted.isInvalid())
return 0;
Failed = true;
llvm::APSInt Cond;
if (VerifyIntegerConstantExpression(Converted.get(), &Cond,
if (!Failed && VerifyIntegerConstantExpression(Converted.get(), &Cond,
diag::err_static_assert_expression_is_not_constant,
/*AllowFold=*/false).isInvalid())
return 0;
Failed = true;
if (!Cond) {
if (!Failed && !Cond) {
llvm::SmallString<256> MsgBuffer;
llvm::raw_svector_ostream Msg(MsgBuffer);
AssertMessage->printPretty(Msg, Context, 0, getPrintingPolicy());
Diag(StaticAssertLoc, diag::err_static_assert_failed)
<< Msg.str() << AssertExpr->getSourceRange();
Failed = true;
}
}
if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression))
return 0;
Decl *Decl = StaticAssertDecl::Create(Context, CurContext, StaticAssertLoc,
AssertExpr, AssertMessage, RParenLoc);
AssertExpr, AssertMessage, RParenLoc,
Failed);
CurContext->addDecl(Decl);
return Decl;

Просмотреть файл

@ -1904,7 +1904,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
continue;
if ((*Member)->isInvalidDecl()) {
Instantiation->setInvalidDecl();
Instantiation->setInvalidDecl();
continue;
}
@ -1928,6 +1928,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
MSInfo->setTemplateSpecializationKind(TSK_ImplicitInstantiation);
MSInfo->setPointOfInstantiation(PointOfInstantiation);
}
} else if (StaticAssertDecl *SA = dyn_cast<StaticAssertDecl>(NewMember)) {
if (SA->isFailed()) {
// A static_assert failed. Bail out; instantiating this
// class is probably not meaningful.
Instantiation->setInvalidDecl();
break;
}
}
if (NewMember->isInvalidDecl())

Просмотреть файл

@ -552,12 +552,11 @@ Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
if (InstantiatedAssertExpr.isInvalid())
return 0;
ExprResult Message(D->getMessage());
D->getMessage();
return SemaRef.ActOnStaticAssertDeclaration(D->getLocation(),
return SemaRef.BuildStaticAssertDeclaration(D->getLocation(),
InstantiatedAssertExpr.get(),
Message.get(),
D->getRParenLoc());
D->getMessage(),
D->getRParenLoc(),
D->isFailed());
}
Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {

Просмотреть файл

@ -1501,7 +1501,8 @@ void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
VisitDecl(D);
D->AssertExpr = Reader.ReadExpr(F);
D->AssertExprAndFailed.setPointer(Reader.ReadExpr(F));
D->AssertExprAndFailed.setInt(Record[Idx++]);
D->Message = cast<StringLiteral>(Reader.ReadExpr(F));
D->RParenLoc = ReadSourceLocation(Record, Idx);
}

Просмотреть файл

@ -1222,6 +1222,7 @@ void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
void ASTDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) {
VisitDecl(D);
Writer.AddStmt(D->getAssertExpr());
Record.push_back(D->isFailed());
Writer.AddStmt(D->getMessage());
Writer.AddSourceLocation(D->getRParenLoc(), Record);
Code = serialization::DECL_STATIC_ASSERT;

Просмотреть файл

@ -34,3 +34,17 @@ static_assert(false, u"\U000317FF"); // expected-error {{static_assert failed u"
static_assert(false, u8"Ω"); // expected-error {{static_assert failed u8"\316\251"}}
static_assert(false, L"\u1234"); // expected-error {{static_assert failed L"\x1234"}}
static_assert(false, L"\x1ff" "0\x123" "fx\xfffff" "goop"); // expected-error {{static_assert failed L"\x1FF""0\x123""fx\xFFFFFgoop"}}
template<typename T> struct AlwaysFails {
// Only give one error here.
static_assert(false, ""); // expected-error {{static_assert failed}}
};
AlwaysFails<int> alwaysFails;
template<typename T> struct StaticAssertProtected {
static_assert(__is_literal(T), ""); // expected-error {{static_assert failed}}
static constexpr T t = {}; // no error here
};
struct X { ~X(); };
StaticAssertProtected<int> sap1;
StaticAssertProtected<X> sap2; // expected-note {{instantiation}}