More static_assert work. Check that the assert expr is valid and show an error if it's false. Create the declaration and add it to the current context.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66995 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj
index 114aa41..48faa12 100644
--- a/clang.xcodeproj/project.pbxproj
+++ b/clang.xcodeproj/project.pbxproj
@@ -548,7 +548,7 @@
 		DEA09A040F302C65000C2258 /* DiagnosticLexKinds.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticLexKinds.def; sourceTree = "<group>"; };
 		DEA09A060F302C65000C2258 /* DiagnosticParseKinds.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticParseKinds.def; sourceTree = "<group>"; };
 		DEA09A080F302C65000C2258 /* DiagnosticSemaKinds.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticSemaKinds.def; sourceTree = "<group>"; };
-		DEA09A6E0F31756F000C2258 /* ASTDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTDiagnostic.h; path = clang/AST/ASTDiagnostic.h; sourceTree = "<group>"; };
+		DEA09A6E0F31756F000C2258 /* ASTDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ASTDiagnostic.h; path = clang/AST/ASTDiagnostic.h; sourceTree = "<group>"; tabWidth = 2; };
 		DEA09A830F3175BF000C2258 /* LexDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LexDiagnostic.h; sourceTree = "<group>"; };
 		DEA09A860F3175CA000C2258 /* ParseDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ParseDiagnostic.h; path = clang/Parse/ParseDiagnostic.h; sourceTree = "<group>"; tabWidth = 2; };
 		DEA09A890F3175D9000C2258 /* SemaDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaDiagnostic.h; path = clang/Sema/SemaDiagnostic.h; sourceTree = "<group>"; };
@@ -556,7 +556,7 @@
 		DEAABDF70F5F477C0098928A /* PrettyStackTrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrettyStackTrace.h; sourceTree = "<group>"; };
 		DEAEE98A0A5A2B970045101B /* MultipleIncludeOpt.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MultipleIncludeOpt.h; sourceTree = "<group>"; };
 		DEAEED4A0A5AF89A0045101B /* NOTES.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = NOTES.txt; sourceTree = "<group>"; };
-		DEB076C90F3A221200F5A2BE /* DeclTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclTemplate.h; path = clang/AST/DeclTemplate.h; sourceTree = "<group>"; };
+		DEB076C90F3A221200F5A2BE /* DeclTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclTemplate.h; path = clang/AST/DeclTemplate.h; sourceTree = "<group>"; tabWidth = 2; };
 		DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclTemplate.cpp; path = lib/AST/DeclTemplate.cpp; sourceTree = "<group>"; };
 		DEB077930F44F96000F5A2BE /* TokenConcatenation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TokenConcatenation.h; sourceTree = "<group>"; };
 		DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TokenConcatenation.cpp; sourceTree = "<group>"; };
@@ -594,7 +594,7 @@
 		DED7D7D70A524302003AD0FB /* README.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = README.txt; sourceTree = "<group>"; };
 		DED7D9170A52518C003AD0FB /* ScratchBuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ScratchBuffer.h; sourceTree = "<group>"; };
 		DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ScratchBuffer.cpp; sourceTree = "<group>"; };
-		DEDFE5270F63A9230035BD10 /* DeclNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DeclNodes.def; path = clang/AST/DeclNodes.def; sourceTree = "<group>"; };
+		DEDFE5270F63A9230035BD10 /* DeclNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = DeclNodes.def; path = clang/AST/DeclNodes.def; sourceTree = "<group>"; tabWidth = 2; };
 		DEEBBD430C19C5D200A9FE82 /* TODO.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = TODO.txt; sourceTree = "<group>"; };
 		DEEBC3B90C2363B800A9FE82 /* CodeGenTypes.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CodeGenTypes.h; path = lib/CodeGen/CodeGenTypes.h; sourceTree = "<group>"; tabWidth = 2; };
 		DEEBC3BB0C2363BC00A9FE82 /* CodeGenTypes.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenTypes.cpp; path = lib/CodeGen/CodeGenTypes.cpp; sourceTree = "<group>"; tabWidth = 2; };
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 7b5eba7..43a91b4 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -886,6 +886,30 @@
   friend class DeclContext;
 };
 
+class StaticAssertDecl : public Decl {
+  SourceLocation AssertLoc;
+
+  Expr *AssertExpr;
+  StringLiteral *Message;
+  
+  StaticAssertDecl(DeclContext *DC, SourceLocation L, 
+                   Expr *assertexpr, StringLiteral *message)
+    : Decl(StaticAssert, DC, L), AssertExpr(assertexpr), Message(message) { }
+  
+public:
+  static StaticAssertDecl *Create(ASTContext &C, DeclContext *DC,
+                                  SourceLocation L, Expr *AssertExpr,
+                                  StringLiteral *Message);
+  
+  virtual ~StaticAssertDecl();
+  virtual void Destroy(ASTContext& C);
+
+  static bool classof(const Decl *D) {
+    return D->getKind() == Decl::StaticAssert;
+  }
+  static bool classof(StaticAssertDecl *D) { return true; }
+};
+  
 } // end namespace clang
 
 #endif
diff --git a/include/clang/AST/DeclNodes.def b/include/clang/AST/DeclNodes.def
index 43bf7f1..d4c8c5e 100644
--- a/include/clang/AST/DeclNodes.def
+++ b/include/clang/AST/DeclNodes.def
@@ -120,6 +120,7 @@
 DECL(ObjCForwardProtocol, Decl)
 DECL(ObjCClass, Decl)
 DECL(FileScopeAsm, Decl)
+DECL(StaticAssert, Decl)
 LAST_DECL(Block, Decl)
 
 // Declaration contexts. DECL_CONTEXT_BASE indicates that it has subclasses.
diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def
index be17a97..4d721bc 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.def
+++ b/include/clang/Basic/DiagnosticSemaKinds.def
@@ -231,6 +231,12 @@
 DIAG(warn_objc_property_attr_mutually_exclusive, WARNING,
      "property attributes '%0' and '%1' are mutually exclusive")
 
+// C++ declarations
+DIAG(err_static_assert_expression_is_not_constant, ERROR,
+    "static_assert expression is not an integral constant expression")
+DIAG(err_static_assert_failed, ERROR,
+    "static_assert failed \"%0\"")
+    
 // C++ name lookup
 DIAG(err_incomplete_nested_name_spec, ERROR,
      "incomplete type %0 named in nested name specifier")
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 3900e38..3df0d1d 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -884,6 +884,7 @@
   virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method) {
   }
 
+  /// ActOnStaticAssertDeclaration - Parse a C++0x static_assert declaration.
   virtual DeclTy *ActOnStaticAssertDeclaration(SourceLocation AssertLoc, 
                                                ExprArg AssertExpr,
                                                ExprArg AssertMessageExpr,
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 4776ce5..fd90083 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -13,6 +13,7 @@
 
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "llvm/ADT/STLExtras.h"
 using namespace clang;
@@ -339,3 +340,19 @@
                                     Used, CommonAncestor);
 }
 
+StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
+                                           SourceLocation L, Expr *AssertExpr,
+                                           StringLiteral *Message) {
+  return new (C) StaticAssertDecl(DC, L, AssertExpr, Message);
+}
+
+void StaticAssertDecl::Destroy(ASTContext& C) {
+  AssertExpr->Destroy(C);
+  Message->Destroy(C);
+  this->~StaticAssertDecl();
+  C.Deallocate((void *)this);
+}
+
+StaticAssertDecl::~StaticAssertDecl() {
+}
+
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index a86aa65..54b3d19 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1554,6 +1554,11 @@
   virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclTy *Param);
   virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method);
 
+  virtual DeclTy *ActOnStaticAssertDeclaration(SourceLocation AssertLoc, 
+                                               ExprArg AssertExpr,
+                                               ExprArg AssertMessageExpr,
+                                               SourceLocation RParenLoc);
+  
   bool CheckConstructorDeclarator(Declarator &D, QualType &R,
                                   FunctionDecl::StorageClass& SC);
   bool CheckConstructor(CXXConstructorDecl *Constructor);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index f5d8f6b..57a6c62 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2234,3 +2234,30 @@
   ProcessDeclAttributes(ExDecl, D);
   return ExDecl;
 }
+
+Sema::DeclTy *Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, 
+                                                 ExprArg assertexpr,
+                                                 ExprArg assertmessageexpr,
+                                                 SourceLocation RParenLoc) {
+  Expr *AssertExpr = (Expr *)assertexpr.get();
+  StringLiteral *AssertMessage = 
+    cast<StringLiteral>((Expr *)assertmessageexpr.get());
+
+  llvm::APSInt Value(32);
+  if (!AssertExpr->isIntegerConstantExpr(Value, Context)) {
+    Diag(AssertLoc, diag::err_static_assert_expression_is_not_constant) <<
+      AssertExpr->getSourceRange();
+    return 0;
+  }
+
+  Decl *Decl = StaticAssertDecl::Create(Context, CurContext, AssertLoc, 
+                                        AssertExpr, AssertMessage);
+  if (Value == 0) {
+    std::string str(AssertMessage->getStrData(), 
+                    AssertMessage->getByteLength());
+    Diag(AssertLoc, diag::err_static_assert_failed) << str;
+  }
+  
+  CurContext->addDecl(Decl);
+  return Decl;
+}
diff --git a/test/SemaCXX/static-assert.cpp b/test/SemaCXX/static-assert.cpp
new file mode 100644
index 0000000..a2b0b52
--- /dev/null
+++ b/test/SemaCXX/static-assert.cpp
@@ -0,0 +1,15 @@
+// RUN: clang -fsyntax-only -verify %s -std=c++0x
+
+int f();
+
+static_assert(f(), "f"); // expected-error {{static_assert expression is not an integral constant expression}}
+static_assert(true, "true is not false");
+static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}}
+
+void g() {
+    static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}}
+}
+
+class C {
+    static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}}
+};