From: Anders Carlsson Date: Sat, 14 Mar 2009 00:25:26 +0000 (+0000) Subject: More static_assert work. Check that the assert expr is valid and show an error if... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fb311762bb52dc015c02cb257d2913f104b556f8;p=clang 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 114aa41ec0..48faa12a70 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 = ""; }; DEA09A060F302C65000C2258 /* DiagnosticParseKinds.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticParseKinds.def; sourceTree = ""; }; DEA09A080F302C65000C2258 /* DiagnosticSemaKinds.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticSemaKinds.def; sourceTree = ""; }; - DEA09A6E0F31756F000C2258 /* ASTDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTDiagnostic.h; path = clang/AST/ASTDiagnostic.h; sourceTree = ""; }; + DEA09A6E0F31756F000C2258 /* ASTDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ASTDiagnostic.h; path = clang/AST/ASTDiagnostic.h; sourceTree = ""; tabWidth = 2; }; DEA09A830F3175BF000C2258 /* LexDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LexDiagnostic.h; sourceTree = ""; }; DEA09A860F3175CA000C2258 /* ParseDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ParseDiagnostic.h; path = clang/Parse/ParseDiagnostic.h; sourceTree = ""; tabWidth = 2; }; DEA09A890F3175D9000C2258 /* SemaDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaDiagnostic.h; path = clang/Sema/SemaDiagnostic.h; sourceTree = ""; }; @@ -556,7 +556,7 @@ DEAABDF70F5F477C0098928A /* PrettyStackTrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrettyStackTrace.h; sourceTree = ""; }; DEAEE98A0A5A2B970045101B /* MultipleIncludeOpt.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MultipleIncludeOpt.h; sourceTree = ""; }; DEAEED4A0A5AF89A0045101B /* NOTES.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = NOTES.txt; sourceTree = ""; }; - DEB076C90F3A221200F5A2BE /* DeclTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclTemplate.h; path = clang/AST/DeclTemplate.h; sourceTree = ""; }; + DEB076C90F3A221200F5A2BE /* DeclTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclTemplate.h; path = clang/AST/DeclTemplate.h; sourceTree = ""; tabWidth = 2; }; DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclTemplate.cpp; path = lib/AST/DeclTemplate.cpp; sourceTree = ""; }; DEB077930F44F96000F5A2BE /* TokenConcatenation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TokenConcatenation.h; sourceTree = ""; }; DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TokenConcatenation.cpp; sourceTree = ""; }; @@ -594,7 +594,7 @@ DED7D7D70A524302003AD0FB /* README.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = README.txt; sourceTree = ""; }; DED7D9170A52518C003AD0FB /* ScratchBuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ScratchBuffer.h; sourceTree = ""; }; DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ScratchBuffer.cpp; sourceTree = ""; }; - DEDFE5270F63A9230035BD10 /* DeclNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DeclNodes.def; path = clang/AST/DeclNodes.def; sourceTree = ""; }; + DEDFE5270F63A9230035BD10 /* DeclNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = DeclNodes.def; path = clang/AST/DeclNodes.def; sourceTree = ""; tabWidth = 2; }; DEEBBD430C19C5D200A9FE82 /* TODO.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = TODO.txt; sourceTree = ""; }; DEEBC3B90C2363B800A9FE82 /* CodeGenTypes.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CodeGenTypes.h; path = lib/CodeGen/CodeGenTypes.h; sourceTree = ""; tabWidth = 2; }; DEEBC3BB0C2363BC00A9FE82 /* CodeGenTypes.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenTypes.cpp; path = lib/CodeGen/CodeGenTypes.cpp; sourceTree = ""; tabWidth = 2; }; diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 7b5eba78f7..43a91b47c7 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -886,6 +886,30 @@ public: 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 43bf7f1023..d4c8c5e6ba 100644 --- a/include/clang/AST/DeclNodes.def +++ b/include/clang/AST/DeclNodes.def @@ -120,6 +120,7 @@ DECL(ObjCPropertyImpl, Decl) 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 be17a9746d..4d721bc331 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -231,6 +231,12 @@ DIAG(error_property_implemented, ERROR, 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 3900e38da7..3df0d1dd7d 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -884,6 +884,7 @@ public: 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 4776ce5877..fd900834ca 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 @@ UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC, 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 a86aa65aff..54b3d197fa 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1554,6 +1554,11 @@ public: 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 f5d8f6b5e1..57a6c62461 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2234,3 +2234,30 @@ Sema::DeclTy *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) 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((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 0000000000..a2b0b52d5d --- /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"}} +};