summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaEquivalence.cpp
diff options
context:
space:
mode:
authorarphaman <arphaman@gmail.com>2013-09-02 17:41:50 +0100
committerarphaman <arphaman@gmail.com>2013-09-02 17:41:50 +0100
commitb8ef6bc3272b6b2661054a96764cc31a97502cb2 (patch)
tree8f09366a1e5fed7dd6d1a2dd8c07fa0aac89be08 /lib/Sema/SemaEquivalence.cpp
parentc11f29b681d02fae6874f1de0eacfce0ff8d9ed0 (diff)
downloadflang-b8ef6bc3272b6b2661054a96764cc31a97502cb2.tar.gz
added construction of equivalence sets
Diffstat (limited to 'lib/Sema/SemaEquivalence.cpp')
-rw-r--r--lib/Sema/SemaEquivalence.cpp118
1 files changed, 104 insertions, 14 deletions
diff --git a/lib/Sema/SemaEquivalence.cpp b/lib/Sema/SemaEquivalence.cpp
index 9612bd5c7d..8b1cf02181 100644
--- a/lib/Sema/SemaEquivalence.cpp
+++ b/lib/Sema/SemaEquivalence.cpp
@@ -19,6 +19,7 @@
#include "flang/AST/Decl.h"
#include "flang/AST/Expr.h"
#include "flang/AST/Stmt.h"
+#include "flang/AST/EquivalenceSet.h"
#include "flang/AST/ExprVisitor.h"
#include "flang/Basic/Diagnostic.h"
@@ -43,6 +44,70 @@ void EquivalenceScope::Connect(Object A, Object B) {
Connections.push_back(Connection(A, B));
}
+class SetCreator {
+ ArrayRef<EquivalenceScope::Connection> Connections;
+ SmallVector<bool, 16> Visited;
+ llvm::SmallVector<EquivalenceScope::Object, 8> Result;
+public:
+
+ SetCreator(ArrayRef<EquivalenceScope::Connection> connections);
+
+ void FindConnections(const EquivalenceScope::InfluenceObject *Obj);
+ bool CreateSet(ASTContext &C);
+};
+
+SetCreator::SetCreator(ArrayRef<EquivalenceScope::Connection> connections)
+ : Connections(connections) {
+ Visited.resize(Connections.size());
+ for(auto &I: Visited) I = false;
+}
+
+void SetCreator::FindConnections(const EquivalenceScope::InfluenceObject *Obj) {
+ for(size_t I = 0; I < Connections.size(); ++I) {
+ if(Visited[I]) continue;
+
+ if(Connections[I].A.Obj == Obj ||
+ Connections[I].B.Obj == Obj) {
+ Visited[I] = true;
+ Result.push_back(Connections[I].A);
+ Result.push_back(Connections[I].B);
+
+ if(Connections[I].A.Obj == Obj)
+ FindConnections(Connections[I].B.Obj);
+ else
+ FindConnections(Connections[I].A.Obj);
+ }
+ }
+}
+
+bool SetCreator::CreateSet(ASTContext &C) {
+ SmallVector<EquivalenceSet::Object, 16> Objects;
+ const EquivalenceScope::InfluenceObject *Obj = nullptr;
+ for(size_t I = 0; I < Connections.size(); ++I) {
+ if(Visited[I]) continue;
+ Obj = Connections[I].A.Obj;
+ }
+ if(!Obj) return false;
+
+ Result.clear();
+ FindConnections(Obj);
+ llvm::SmallPtrSet<VarDecl*, 16> ProcessedObjects;
+ for(auto I : Result) {
+ if(ProcessedObjects.insert(I.Obj->Var))
+ Objects.push_back(EquivalenceSet::Object(I.Obj->Var, I.E));
+ }
+
+ auto Set = EquivalenceSet::Create(C, Objects);
+ for(auto I : Objects)
+ I.Var->setEquivalenceSet(Set);
+ return true;
+}
+
+void EquivalenceScope::CreateEquivalenceSets(ASTContext &C) {
+ SetCreator Creator(Connections);
+ while(Creator.CreateSet(C)) ;
+}
+
class ConnectionFinder {
ArrayRef<EquivalenceScope::Connection> Connections;
SmallVector<bool, 16> Visited;
@@ -68,11 +133,11 @@ void ConnectionFinder::FindRelevantConnections(EquivalenceScope::Object Point,
EquivalenceScope::Object Target) {
for(size_t I = 0; I < Connections.size(); ++I) {
if(Visited[I]) continue;
- Visited[I] = true;
// given (a - b), found (a - x) or (x - a)
if(Connections[I].A.Obj == Point.Obj ||
Connections[I].B.Obj == Point.Obj) {
+ Visited[I] = true;
auto Other = Connections[I].A.Obj == Point.Obj? Connections[I].B :
Connections[I].A;
@@ -88,25 +153,50 @@ void ConnectionFinder::FindRelevantConnections(EquivalenceScope::Object Point,
}
}
-bool EquivalenceScope::CheckConnection(DiagnosticsEngine &Diags, Object A, Object B) {
+bool EquivalenceScope::CheckConnection(DiagnosticsEngine &Diags, Object A, Object B, bool ReportWarnings) {
// equivalence (x,x)
if(A.Obj == B.Obj) {
- Diags.Report(B.E->getLocation(), diag::warn_equivalence_same_object)
- << A.E->getSourceRange()
- << B.E->getSourceRange();
+ if(ReportWarnings) {
+ Diags.Report(B.E->getLocation(), diag::warn_equivalence_same_object)
+ << A.E->getSourceRange() << B.E->getSourceRange();
+ ReportWarnings = false;
+ }
}
//
ConnectionFinder Finder(Connections);
Finder.FindRelevantConnections(A, B);
auto Relevant = Finder.getResults();
if (!Relevant.empty()) {
- Diags.Report(B.E->getLocation(), diag::warn_equivalence_redundant)
- << A.E->getSourceRange()
- << B.E->getSourceRange();
- auto I = Relevant.front();
- Diags.Report(I.A.E->getLocation(), diag::note_equivalence_identical_association)
- << I.A.E->getSourceRange()
- << I.B.E->getSourceRange();
+
+ for(auto I : Relevant) {
+ bool same = true;
+ if(B.Obj == I.A.Obj)
+ same = B.Offset == I.A.Offset;
+ else if(B.Obj == I.B.Obj)
+ same = B.Offset == I.B.Offset;
+ if(same) {
+ if(A.Obj == I.A.Obj)
+ same = A.Offset == I.A.Offset;
+ else if(A.Obj == I.B.Obj)
+ same = A.Offset == I.B.Offset;
+ }
+ if(!same) {
+ Diags.Report(B.E->getLocation(), diag::err_equivalence_conflicting_offsets)
+ << A.E->getSourceRange() << B.E->getSourceRange();
+ Diags.Report(I.A.E->getLocation(), diag::note_equivalence_prev_offset)
+ << I.A.E->getSourceRange() << I.B.E->getSourceRange();
+ return false;
+ }
+ }
+
+ if(ReportWarnings) {
+ Diags.Report(B.E->getLocation(), diag::warn_equivalence_redundant)
+ << A.E->getSourceRange() << B.E->getSourceRange();
+ auto I = Relevant.front();
+ Diags.Report(I.A.E->getLocation(), diag::note_equivalence_identical_association)
+ << I.A.E->getSourceRange() << I.B.E->getSourceRange();
+ ReportWarnings = false;
+ }
}
return true;
}
@@ -177,11 +267,11 @@ StmtResult Sema::ActOnEQUIVALENCE(ASTContext &C, SourceLocation Loc,
ArrayRef<Expr*> ObjectList,
Expr *StmtLabel) {
// expression and type check.
- bool HasErrors = false;
QualType ObjectType;
EquivalenceScope::Object FirstEquivObject;
for(auto I : ObjectList) {
+ bool HasErrors = false;
VarDecl *Object = nullptr;
uint64_t Offset = 0;
if(auto Arr = dyn_cast<ArrayElementExpr>(I)) {
@@ -218,7 +308,7 @@ StmtResult Sema::ActOnEQUIVALENCE(ASTContext &C, SourceLocation Loc,
if(CheckEquivalenceType(ObjectType, I))
HasErrors = true;
auto EquivObject = getCurrentEquivalenceScope()->GetObject(C, I, Object, Offset);
- if(getCurrentEquivalenceScope()->CheckConnection(Diags, FirstEquivObject, EquivObject))
+ if(getCurrentEquivalenceScope()->CheckConnection(Diags, FirstEquivObject, EquivObject, !HasErrors))
getCurrentEquivalenceScope()->Connect(FirstEquivObject,
EquivObject);
}