зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
18b7f95bdb
Коммит
e3f470a718
|
@ -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}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче