summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorarphaman <arphaman@gmail.com>2013-09-20 15:59:20 +0100
committerarphaman <arphaman@gmail.com>2013-09-20 15:59:20 +0100
commit6ba4866e1096d45a83a5d92ecac7e902b897f3e9 (patch)
tree206c403933ef651bb3524a57e9f43ac5641a6b65
parentf87f0988b80f3a886d7b93d93d6e31ecd15b8f01 (diff)
downloadflang-6ba4866e1096d45a83a5d92ecac7e902b897f3e9.tar.gz
added sema for COMMON
-rw-r--r--include/flang/AST/Decl.h30
-rw-r--r--include/flang/AST/StorageSet.h12
-rw-r--r--include/flang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--include/flang/Sema/Scope.h24
-rw-r--r--include/flang/Sema/Sema.h3
-rw-r--r--lib/AST/Stmt.cpp19
-rw-r--r--lib/CodeGen/CGDecl.cpp13
-rw-r--r--lib/Sema/Scope.cpp8
-rw-r--r--lib/Sema/SemaEquivalence.cpp2
-rw-r--r--lib/Sema/Spec.cpp47
-rw-r--r--test/Sema/common.f9510
11 files changed, 145 insertions, 26 deletions
diff --git a/include/flang/AST/Decl.h b/include/flang/AST/Decl.h
index cbe8698894..e8755cd7e3 100644
--- a/include/flang/AST/Decl.h
+++ b/include/flang/AST/Decl.h
@@ -37,7 +37,9 @@ class IdentifierInfo;
class StoredDeclsMap;
class TypeLoc;
class BlockStmt;
+class StorageSet;
class EquivalenceSet;
+class CommonBlockSet;
// Decls
class DeclContext;
@@ -937,15 +939,15 @@ private:
/// \brief The initializer for this variable.
mutable Expr *Init;
- /// \brief The equivalence set for this variable.
- EquivalenceSet *EquivSet;
+ /// \brief The storage set for this variable.
+ StorageSet *Storage;
friend class ASTContext; // ASTContext creates these.
protected:
VarDecl(Kind DK, DeclContext *DC, SourceLocation IdLoc, const IdentifierInfo *ID,
QualType T)
- : DeclaratorDecl(DK, DC, IdLoc, ID, T), Init(nullptr), EquivSet(nullptr) {}
+ : DeclaratorDecl(DK, DC, IdLoc, ID, T), Init(nullptr), Storage(nullptr) {}
public:
static VarDecl *Create(ASTContext &C, DeclContext *DC,
@@ -980,12 +982,12 @@ public:
void MutateIntoParameter(Expr *Value);
void MarkUsedAsVariable (SourceLocation Loc);
- EquivalenceSet *getEquivalenceSet() const { return EquivSet; }
- bool hasEquivalenceSet() const {
- return EquivSet != nullptr;
+ StorageSet *getStorageSet() const { return Storage; }
+ bool hasStorageSet() const {
+ return Storage != nullptr;
}
- void setEquivalenceSet(EquivalenceSet *E) {
- EquivSet = E;
+ void setStorageSet(StorageSet *S) {
+ Storage = S;
}
// Implement isa/cast/dyncast/etc.
@@ -1004,13 +1006,23 @@ public:
};
class CommonBlockDecl : public NamedDecl {
+ CommonBlockSet *Set;
+
CommonBlockDecl(DeclContext *DC,
SourceLocation IDLoc, const IdentifierInfo *IDInfo)
- : NamedDecl(CommonBlock, DC, IDLoc, DeclarationName(IDInfo)) {}
+ : NamedDecl(CommonBlock, DC, IDLoc, DeclarationName(IDInfo)),
+ Set(nullptr) {}
public:
static CommonBlockDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation IDLoc, const IdentifierInfo *IDInfo);
+ CommonBlockSet *getStorageSet() const {
+ return Set;
+ }
+ void setStorageSet(CommonBlockSet *S) {
+ Set = S;
+ }
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const CommonBlockDecl *D) { return true; }
static bool classofKind(Kind K) { return K == CommonBlock; }
diff --git a/include/flang/AST/StorageSet.h b/include/flang/AST/StorageSet.h
index 1e454761b4..de28e508d5 100644
--- a/include/flang/AST/StorageSet.h
+++ b/include/flang/AST/StorageSet.h
@@ -20,6 +20,7 @@ namespace flang {
class ASTContext;
class VarDecl;
+class CommonBlockDecl;
class Expr;
/// StorageSet - A
@@ -89,16 +90,23 @@ public:
private:
Object *Objects;
unsigned ObjectCount;
+ CommonBlockDecl *Decl;
- CommonBlockSet(ASTContext &C, ArrayRef<Object> objects);
+ CommonBlockSet(CommonBlockDecl *CBDecl);
public:
- static CommonBlockSet *Create(ASTContext &C, ArrayRef<Object> Objects);
+ static CommonBlockSet *Create(flang::ASTContext &C, CommonBlockDecl *CBDecl);
+
+ void setObjects(ASTContext &C, ArrayRef<Object> objects);
ArrayRef<Object> getObjects() const {
return ArrayRef<Object>(Objects, ObjectCount);
}
+ CommonBlockDecl *getDecl() const {
+ return Decl;
+ }
+
static bool classof(const StorageSet* S) {
return S->getStorageSetClass() == CommonBlockSetClass;
}
diff --git a/include/flang/Basic/DiagnosticSemaKinds.td b/include/flang/Basic/DiagnosticSemaKinds.td
index f6218e9759..e155baca95 100644
--- a/include/flang/Basic/DiagnosticSemaKinds.td
+++ b/include/flang/Basic/DiagnosticSemaKinds.td
@@ -286,6 +286,8 @@ def err_spec_dimension_already_array : Error<
"the specification statement 'dimension' cannot be applied to the array variable %0">;
def err_spec_qual_reapplication : Error<
"the specification statement '%0' cannot be applied to the variable %1 more than once">;
+def err_spec_not_applicable_to_common_block : Error<
+ "the specification statement '%0' cannot be applied to a variable in common block">;
def warn_equivalence_same_object : Warning<
"this equivalence connection uses the same object">;
@@ -298,7 +300,6 @@ def err_equivalence_conflicting_offsets : Error<
def note_equivalence_prev_offset : Note<
"previous memory offset was defined here">;
-
def err_format_without_stmt_label : Error<
"'FORMAT' statement is missing a statement label">;
diff --git a/include/flang/Sema/Scope.h b/include/flang/Sema/Scope.h
index 983d5136a8..3fff72d0b2 100644
--- a/include/flang/Sema/Scope.h
+++ b/include/flang/Sema/Scope.h
@@ -310,10 +310,27 @@ public:
/// statement.
///
class CommonBlockScope {
+public:
+ typedef llvm::SmallDenseMap<const IdentifierInfo*, CommonBlockDecl*> BlockMappingTy;
+private:
CommonBlockDecl *UnnamedBlock;
- llvm::SmallDenseMap<const IdentifierInfo*, CommonBlockDecl*> Blocks;
+ BlockMappingTy Blocks;
public:
+ bool hasUnnamed() const {
+ return UnnamedBlock != nullptr;
+ }
+ CommonBlockDecl *getUnnamed() const {
+ return UnnamedBlock;
+ }
+
+ BlockMappingTy::const_iterator beginNamed() const {
+ return Blocks.begin();
+ }
+ BlockMappingTy::const_iterator endNamed() const {
+ return Blocks.end();
+ }
+
CommonBlockDecl *find(const IdentifierInfo *IDInfo);
CommonBlockDecl *findOrInsert(ASTContext &C, DeclContext *DC,
@@ -321,6 +338,8 @@ public:
const IdentifierInfo *IDInfo);
};
+class CommonBlockSetBuilder;
+
/// The scope which helps to apply specification statements
class SpecificationScope {
@@ -374,7 +393,8 @@ public:
const IdentifierInfo *IDInfo,
CommonBlockDecl *Block);
- void ApplyCommonSpecs(Sema &Visitor);
+ void ApplyCommonSpecs(Sema &Visitor,
+ CommonBlockSetBuilder &Builder);
};
/// The scope of a translation unit (a single file)
diff --git a/include/flang/Sema/Sema.h b/include/flang/Sema/Sema.h
index 42de56bc31..75262a4a4d 100644
--- a/include/flang/Sema/Sema.h
+++ b/include/flang/Sema/Sema.h
@@ -210,7 +210,8 @@ public:
bool ApplyCommonSpecification(SourceLocation Loc, SourceLocation IDLoc,
const IdentifierInfo *IDInfo,
- CommonBlockDecl *Block);
+ CommonBlockDecl *Block,
+ CommonBlockSetBuilder &Builder);
QualType ActOnTypeName(ASTContext &C, DeclSpec &DS);
VarDecl *ActOnKindSelector(ASTContext &C, SourceLocation IDLoc,
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 8d80506e65..bc294d731b 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -299,6 +299,25 @@ EquivalenceSet *EquivalenceSet::Create(ASTContext &C, ArrayRef<Object> Objects)
}
//===----------------------------------------------------------------------===//
+// Common Statement
+//===----------------------------------------------------------------------===//
+
+CommonBlockSet::CommonBlockSet(CommonBlockDecl *CBDecl)
+ : StorageSet(CommonBlockSetClass), Decl(CBDecl),
+ ObjectCount(0) { }
+
+CommonBlockSet *CommonBlockSet::Create(ASTContext &C, CommonBlockDecl *CBDecl) {
+ return new(C) CommonBlockSet(CBDecl);
+}
+
+void CommonBlockSet::setObjects(ASTContext &C, ArrayRef<Object> objects) {
+ ObjectCount = objects.size();
+ Objects = new(C) Object[ObjectCount];
+ for(size_t I = 0; I < ObjectCount; ++I)
+ Objects[I] = objects[I];
+}
+
+//===----------------------------------------------------------------------===//
// Data Statement
//===----------------------------------------------------------------------===//
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 8a2cd310ce..1a1976c4a3 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -41,10 +41,15 @@ void CodeGenFunction::EmitVarDecl(const VarDecl *D) {
D->isArgument() ||
D->isFunctionResult()) return;
- if(D->hasEquivalenceSet()) {
- auto Set = EmitEquivalenceSet(D->getEquivalenceSet());
- auto Ptr = EmitEquivalenceSetObject(Set, D);
- LocalVariables.insert(std::make_pair(D, Ptr));
+ if(D->hasStorageSet()) {
+ if(auto E = dyn_cast<EquivalenceSet>(D->getStorageSet())) {
+ auto Set = EmitEquivalenceSet(E);
+ auto Ptr = EmitEquivalenceSetObject(Set, D);
+ LocalVariables.insert(std::make_pair(D, Ptr));
+ } else if(auto C = dyn_cast<CommonBlockSet>(D->getStorageSet())) {
+ // FIXME
+ } else
+ llvm_unreachable("invalid storage set");
return;
}
diff --git a/lib/Sema/Scope.cpp b/lib/Sema/Scope.cpp
index 6401aed4a3..2446cb33b6 100644
--- a/lib/Sema/Scope.cpp
+++ b/lib/Sema/Scope.cpp
@@ -14,6 +14,7 @@
#include "flang/Sema/Scope.h"
#include "flang/AST/Expr.h"
+#include "flang/AST/StorageSet.h"
#include <limits>
namespace flang {
@@ -165,14 +166,19 @@ CommonBlockDecl *CommonBlockScope::findOrInsert(ASTContext &C, DeclContext *DC,
SourceLocation IDLoc,
const IdentifierInfo *IDInfo) {
if(!IDInfo) {
- if(!UnnamedBlock)
+ if(!UnnamedBlock) {
UnnamedBlock = CommonBlockDecl::Create(C, DC, IDLoc, IDInfo);
+ auto Set = CommonBlockSet::Create(C, UnnamedBlock);
+ UnnamedBlock->setStorageSet(Set);
+ }
return UnnamedBlock;
}
auto Result = Blocks.find(IDInfo);
if(Result != Blocks.end())
return Result->second;
auto Block = CommonBlockDecl::Create(C, DC, IDLoc, IDInfo);
+ auto Set = CommonBlockSet::Create(C, Block);
+ Block->setStorageSet(Set);
Blocks.insert(std::make_pair(IDInfo, Block));
return Block;
}
diff --git a/lib/Sema/SemaEquivalence.cpp b/lib/Sema/SemaEquivalence.cpp
index 9a72ec41cd..07d2a2fe91 100644
--- a/lib/Sema/SemaEquivalence.cpp
+++ b/lib/Sema/SemaEquivalence.cpp
@@ -99,7 +99,7 @@ bool SetCreator::CreateSet(ASTContext &C) {
auto Set = EquivalenceSet::Create(C, Objects);
for(auto I : Objects)
- I.Var->setEquivalenceSet(Set);
+ I.Var->setStorageSet(Set);
return true;
}
diff --git a/lib/Sema/Spec.cpp b/lib/Sema/Spec.cpp
index 9f8131191e..dc66d912db 100644
--- a/lib/Sema/Spec.cpp
+++ b/lib/Sema/Spec.cpp
@@ -19,6 +19,7 @@
#include "flang/AST/Decl.h"
#include "flang/AST/Expr.h"
#include "flang/AST/Stmt.h"
+#include "flang/AST/StorageSet.h"
#include "flang/Basic/Diagnostic.h"
#include "llvm/Support/raw_ostream.h"
@@ -157,6 +158,13 @@ bool Sema::ApplySaveSpecification(SourceLocation Loc, SourceLocation IDLoc,
bool Sema::ApplySaveSpecification(SourceLocation Loc, SourceLocation IDLoc,
VarDecl *VD) {
+ if(VD->hasStorageSet()) {
+ if(auto CBSet = dyn_cast<CommonBlockSet>(VD->getStorageSet())) {
+ Diags.Report(Loc, diag::err_spec_not_applicable_to_common_block)
+ << "save" << getTokenRange(IDLoc);
+ return true;
+ }
+ }
auto Type = VD->getType();
auto Quals = Type.getQualifiers();
if(Quals.hasAttributeSpec(Qualifiers::AS_save)) {
@@ -186,17 +194,44 @@ void SpecificationScope::AddCommonSpec(SourceLocation Loc, SourceLocation IDLoc,
CommonSpecs.push_back(Spec);
}
-void SpecificationScope::ApplyCommonSpecs(Sema &Visitor) {
+class CommonBlockSetBuilder {
+public:
+ llvm::SmallDenseMap<CommonBlockDecl*,
+ SmallVector<CommonBlockSet::Object, 16>, 8> Sets;
+
+ void Add(CommonBlockDecl *CBDecl, CommonBlockSet::Object Object) {
+ Sets.insert(std::make_pair(CBDecl,SmallVector<CommonBlockSet::Object, 16>())).first->second.push_back(Object);
+ }
+
+ void CreateSets(ASTContext &C) {
+ for(auto Set : Sets)
+ Set.first->getStorageSet()->setObjects(C, Set.second);
+ }
+};
+
+void SpecificationScope::ApplyCommonSpecs(Sema &Visitor, CommonBlockSetBuilder &Builder) {
for(auto Spec : CommonSpecs)
Visitor.ApplyCommonSpecification(Spec.Loc, Spec.IDLoc,
- Spec.IDInfo, Spec.Block);
+ Spec.IDInfo, Spec.Block,
+ Builder);
}
bool Sema::ApplyCommonSpecification(SourceLocation Loc, SourceLocation IDLoc,
const IdentifierInfo *IDInfo,
- CommonBlockDecl *Block) {
+ CommonBlockDecl *Block, CommonBlockSetBuilder &Builder) {
auto VD = GetVariableForSpecification(Loc, IDInfo, IDLoc);
if(!VD) return true;
+ if(VD->hasStorageSet()) {
+ if(auto CBSet = dyn_cast<CommonBlockSet>(VD->getStorageSet())) {
+ Diags.Report(Loc, diag::err_spec_qual_reapplication)
+ << "common" << IDInfo
+ << getTokenRange(IDLoc);
+ return true;
+ }
+ // FIXME: COMMON + EQUIVALENCE
+ }
+ Builder.Add(Block, CommonBlockSet::Object(VD));
+ VD->setStorageSet(Block->getStorageSet());
return false;
}
@@ -205,7 +240,11 @@ void Sema::ActOnSpecificationPart() {
ActOnFunctionSpecificationPart();
CurSpecScope->ApplyDimensionSpecs(*this);
- CurSpecScope->ApplyCommonSpecs(*this);
+
+ CommonBlockSetBuilder CBBuilder;
+ CurSpecScope->ApplyCommonSpecs(*this, CBBuilder);
+ CBBuilder.CreateSets(Context);
+
CurSpecScope->ApplySaveSpecs(*this);
}
diff --git a/test/Sema/common.f95 b/test/Sema/common.f95
index 00a3f4f807..ae61691290 100644
--- a/test/Sema/common.f95
+++ b/test/Sema/common.f95
@@ -27,5 +27,13 @@ end
subroutine sub3
integer i
common /a/i
- save i ! expected-error {{}}
+ save i ! expected-error {{the specification statement 'save' cannot be applied to a variable in common block}}
+end
+
+subroutine sub4
+ integer i,j
+ common i
+ common /a/i,j ! expected-error {{the specification statement 'common' cannot be applied to the variable 'i' more than once}}
+ common j ! expected-error {{the specification statement 'common' cannot be applied to the variable 'j' more than once}}
+ common /b/i ! expected-error {{the specification statement 'common' cannot be applied to the variable 'i' more than once}}
end