]> granicus.if.org Git - clang/commitdiff
Stop instantiating a class if we hit a static_assert failure. Also, if the
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 11 Jul 2012 22:37:56 +0000 (22:37 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 11 Jul 2012 22:37:56 +0000 (22:37 +0000)
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

include/clang/AST/DeclCXX.h
include/clang/Sema/Sema.h
lib/AST/DeclCXX.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriterDecl.cpp
test/SemaCXX/static-assert.cpp

index 9130e28a47bcf98c2224bdd7f750203a36b3b799..0d498fe4e571672f2352bb307b7d9c0e8121add2 100644 (file)
@@ -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());
index 6096466f08062f64eae6af69f66831fe56d45734..35bbc0104f598051f7f3667915587d4174d561f9 100644 (file)
@@ -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,
index 11a5260836af37b8dea1e5e1817b57d2567e6dfe..77e693c2c7492dc9b88ad106cd575ef28bff2d37 100644 (file)
@@ -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) {
index fa42fdd827c2ae32156545e272b759485dabf93e..ebd9180ec64dae3433c370b1e1eedda8b9fa074d 100644 (file)
@@ -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;
index 239a0d73ebc3cdccded2ad7e2b82eb1b85bcf29e..0a0016c50b3f94da50dcf21bf6a0d55849a7aba9 100644 (file)
@@ -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())
index cce0b0d0930a6a30ded40065b1ed125c7cb46979..0d3e8a0ba8e0145d85a058a80f9408c12b7ba4f9 100644 (file)
@@ -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) {
index f5f9ba25988a719a85da8489f591aa160df645c5..25f89adc7fa5dacf8f61c113df3f9f0fc2085615 100644 (file)
@@ -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);
 }
index 96b602221ebdb8052270ddf060774890d51f75fb..21ba4d0374e16bd691913dc7bdf5dc157bf8551a 100644 (file)
@@ -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;
index 364e4e4bef37f9c698a7f77cbfd6d609599cd3ed..4a7560ba5b6a2bd57deb75aa3a83d553116aa98f 100644 (file)
@@ -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}}