diff options
author | arphaman <arphaman@gmail.com> | 2013-09-15 12:50:50 +0100 |
---|---|---|
committer | arphaman <arphaman@gmail.com> | 2013-09-15 12:50:50 +0100 |
commit | 2cf3fb6ca004470326987a6392555082945d0b36 (patch) | |
tree | 1f0670d0ef349bccd1f93b447ca2b3e0dff60977 | |
parent | f9193d5550ca1ab9e801d1f2e5ab3d49dba1b0d0 (diff) | |
download | flang-2cf3fb6ca004470326987a6392555082945d0b36.tar.gz |
improved sema for declaration attributes
-rw-r--r-- | include/flang/Sema/Sema.h | 21 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 200 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 240 | ||||
-rw-r--r-- | test/Sema/declarationAttributes.f95 | 11 |
4 files changed, 266 insertions, 206 deletions
diff --git a/include/flang/Sema/Sema.h b/include/flang/Sema/Sema.h index 5267d5354e..0053f29d71 100644 --- a/include/flang/Sema/Sema.h +++ b/include/flang/Sema/Sema.h @@ -226,11 +226,21 @@ public: void ActOnTypeDeclSpec(ASTContext &C, SourceLocation Loc, const IdentifierInfo *IDInfo, DeclSpec &DS); - Decl *ActOnEntityDecl(ASTContext &C, const QualType &T, SourceLocation IDLoc, - const IdentifierInfo *IDInfo); + Decl *ActOnExternalEntityDecl(ASTContext &C, QualType T, + SourceLocation IDLoc, const IdentifierInfo *IDInfo); - Decl *ActOnEntityDecl(ASTContext &C, DeclSpec &DS, SourceLocation IDLoc, - const IdentifierInfo *IDInfo); + Decl *ActOnIntrinsicEntityDecl(ASTContext &C, QualType T, + SourceLocation IDLoc, const IdentifierInfo *IDInfo); + + Decl *ActOnParameterEntityDecl(ASTContext &C, QualType T, + SourceLocation IDLoc, const IdentifierInfo *IDInfo, + SourceLocation EqualLoc, ExprResult Value); + + Decl *ActOnEntityDecl(ASTContext &C, const QualType &T, + SourceLocation IDLoc, const IdentifierInfo *IDInfo); + + Decl *ActOnEntityDecl(ASTContext &C, DeclSpec &DS, + SourceLocation IDLoc, const IdentifierInfo *IDInfo); QualType ResolveImplicitType(const IdentifierInfo *IDInfo); @@ -646,6 +656,9 @@ public: /// Returns true if the declaration with the given name is valid. bool CheckDeclaration(const IdentifierInfo *IDInfo, SourceLocation IDLoc); + void DiagnoseRedefinition(SourceLocation Loc, const IdentifierInfo *IDInfo, + Decl *Prev); + /// Returns evaluated integer, /// or an ErrorValue if the expression couldn't /// be evaluated. diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 780717b367..1d4a8e3e8d 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -461,64 +461,6 @@ void Sema::ActOnEndStatementFunction(ASTContext &C) { PopDeclContext(); } -/// \brief Convert the specified DeclSpec to the appropriate type object. -QualType Sema::ActOnTypeName(ASTContext &C, DeclSpec &DS) { - QualType Result; - switch (DS.getTypeSpecType()) { - case DeclSpec::TST_integer: - Result = C.IntegerTy; - break; - case DeclSpec::TST_unspecified: // FIXME: Correct? - case DeclSpec::TST_real: - Result = C.RealTy; - break; - case DeclSpec::TST_character: - Result = C.CharacterTy; - break; - case DeclSpec::TST_logical: - Result = C.LogicalTy; - break; - case DeclSpec::TST_complex: - Result = C.ComplexTy; - break; - case DeclSpec::TST_struct: - if(!DS.getRecord()) - Result = C.RealTy; - else - Result = C.getRecordType(DS.getRecord()); - break; - } - - if (!DS.hasAttributes()) - return Result; - - const Type *TypeNode = Result.getTypePtr(); - Qualifiers Quals = Qualifiers::fromOpaqueValue(DS.getAttributeSpecs()); - Quals.setIntentAttr(DS.getIntentSpec()); - Quals.setAccessAttr(DS.getAccessSpec()); - - unsigned Kind = BuiltinType::NoKind; - if(DS.isDoublePrecision()) { - assert(!DS.getKindSelector()); - Kind = BuiltinType::Real8; - } else if(DS.hasKindSelector()) - Kind = EvalAndCheckTypeKind(Result, DS.getKindSelector()); - - unsigned LengthSelector = 0; - if(DS.hasLengthSelector() && !DS.isStarLengthSelector()) - LengthSelector = EvalAndCheckCharacterLength(DS.getLengthSelector()); - - Result = C.getExtQualType(TypeNode, Quals, Kind, - DS.isDoublePrecision(), - DS.isStarLengthSelector(), - LengthSelector); - - if (!Quals.hasAttributeSpec(Qualifiers::AS_dimension)) - return Result; - - return ActOnArraySpec(C, Result, DS.getDimensions()); -} - VarDecl *Sema::ActOnKindSelector(ASTContext &C, SourceLocation IDLoc, const IdentifierInfo *IDInfo) { VarDecl *VD = VarDecl::Create(C, CurContext, IDLoc, IDInfo, QualType()); @@ -529,55 +471,6 @@ VarDecl *Sema::ActOnKindSelector(ASTContext &C, SourceLocation IDLoc, return VD; } -Decl *Sema::ActOnEntityDecl(ASTContext &C, const QualType &T, SourceLocation IDLoc, - const IdentifierInfo *IDInfo) { - if (auto Prev = LookupIdentifier(IDInfo)) { - FunctionDecl *FD = dyn_cast<FunctionDecl>(Prev); - if(auto VD = dyn_cast<VarDecl>(Prev)) { - if(VD->isArgument() && VD->getType().isNull()) { - VD->setType(T); - return VD; - } else if(VD->isFunctionResult()) - FD = CurrentContextAsFunction(); - } - - if(FD && (FD->isNormalFunction() || FD->isExternal())) { - if(FD->getType().isNull()) { - SetFunctionType(FD, T, IDLoc, SourceRange()); //Fixme: proper loc and range - return FD; - } else { - Diags.Report(IDLoc, diag::err_func_return_type_already_specified) << IDInfo; - return nullptr; - } - } - Diags.Report(IDLoc, diag::err_redefinition) << IDInfo; - Diags.Report(Prev->getLocation(), diag::note_previous_definition); - return nullptr; - } - - VarDecl *VD = VarDecl::Create(C, CurContext, IDLoc, IDInfo, T); - CurContext->addDecl(VD); - - if(!T.isNull()) { - auto SubT = T; - if(T->isArrayType()) { - CheckArrayTypeDeclarationCompability(T->asArrayType(), VD); - SubT = T->asArrayType()->getElementType(); - VD->MarkUsedAsVariable(IDLoc); - } - else if(SubT->isCharacterType()) - CheckCharacterLengthDeclarationCompability(SubT, VD); - } - - return VD; -} - -Decl *Sema::ActOnEntityDecl(ASTContext &C, DeclSpec &DS, SourceLocation IDLoc, - const IdentifierInfo *IDInfo) { - QualType T = ActOnTypeName(C, DS); - return ActOnEntityDecl(C, T, IDLoc, IDInfo); -} - QualType Sema::ResolveImplicitType(const IdentifierInfo *IDInfo) { auto Result = getCurrentImplicitTypingScope()->Resolve(IDInfo); if(Result.first == ImplicitTypingScope::NoneRule) return QualType(); @@ -844,44 +737,8 @@ StmtResult Sema::ActOnPARAMETER(ASTContext &C, SourceLocation Loc, SourceLocation IDLoc, const IdentifierInfo *IDInfo, ExprResult Value, Expr *StmtLabel) { - VarDecl *VD = nullptr; - if (auto Prev = LookupIdentifier(IDInfo)) { - VD = dyn_cast<VarDecl>(Prev); - if(!VD || VD->isParameter()) { - Diags.Report(IDLoc, diag::err_redefinition) << IDInfo; - Diags.Report(Prev->getLocation(), diag::note_previous_definition); - return StmtError(); - } - } - - // Make sure the value is a constant expression. - if(!Value.get()->isEvaluatable(C)) { - llvm::SmallVector<const Expr*, 16> Results; - Value.get()->GatherNonEvaluatableExpressions(C, Results); - Diags.Report(IDLoc, diag::err_parameter_requires_const_init) - << IDInfo << Value.get()->getSourceRange(); - for(auto E : Results) { - Diags.Report(E->getLocation(), diag::note_parameter_value_invalid_expr) - << E->getSourceRange(); - } - return StmtError(); - } - - if(VD) { - Value = TypecheckAssignment(VD->getType(), Value, - EqualLoc, - getTokenRange(IDLoc), - Value.get()->getSourceRange()); - if(Value.isInvalid()) return StmtError(); - // FIXME: if value is invalid, mutate into parameter givin a zero value - VD->MutateIntoParameter(Value.get()); - } else { - QualType T = Value.get()->getType(); - VD = VarDecl::Create(C, CurContext, IDLoc, IDInfo, T); - VD->MutateIntoParameter(Value.get()); - CurContext->addDecl(VD); - } + ActOnParameterEntityDecl(C, QualType(), IDLoc, IDInfo, EqualLoc, Value); auto Result = ParameterStmt::Create(C, Loc, IDInfo, Value.get(), StmtLabel); if(StmtLabel) DeclareStatementLabel(StmtLabel, Result); @@ -909,33 +766,7 @@ StmtResult Sema::ActOnDIMENSION(ASTContext &C, SourceLocation Loc, StmtResult Sema::ActOnEXTERNAL(ASTContext &C, SourceLocation Loc, SourceLocation IDLoc, const IdentifierInfo *IDInfo, Expr *StmtLabel) { - QualType Type; - SourceLocation TypeLoc; - VarDecl *ArgumentExternal = nullptr; - if (auto Prev = LookupIdentifier(IDInfo)) { - auto VD = dyn_cast<VarDecl>(Prev); - if(VD && (VD->isUnusedSymbol() || VD->isArgument()) ) { - Type = VD->getType(); - TypeLoc = VD->getLocation(); - CurContext->removeDecl(VD); - if(VD->isArgument()) - ArgumentExternal = VD; - } else { - Diags.Report(IDLoc, diag::err_redefinition) << IDInfo; - Diags.Report(Prev->getLocation(), diag::note_previous_definition); - return StmtError(); - } - } - - DeclarationNameInfo DeclName(IDInfo,IDLoc); - auto Decl = FunctionDecl::Create(C, ArgumentExternal? FunctionDecl::ExternalArgument : - FunctionDecl::External, - CurContext, DeclName, Type); - if(!Type.isNull()) - SetFunctionType(Decl, Type, TypeLoc, SourceRange()); //FIXME: proper loc, and range - CurContext->addDecl(Decl); - if(ArgumentExternal) - ArgumentExternal->setType(C.getFunctionType(Decl)); + ActOnExternalEntityDecl(C, QualType(), IDLoc, IDInfo); auto Result = ExternalStmt::Create(C, IDLoc, IDInfo, StmtLabel); if(StmtLabel) DeclareStatementLabel(StmtLabel, Result); @@ -946,32 +777,7 @@ StmtResult Sema::ActOnINTRINSIC(ASTContext &C, SourceLocation Loc, SourceLocation IDLoc, const IdentifierInfo *IDInfo, Expr *StmtLabel) { - auto FuncResult = IntrinsicFunctionMapping.Resolve(IDInfo); - if(FuncResult.IsInvalid) { - Diags.Report(IDLoc, diag::err_intrinsic_invalid_func) - << IDInfo - << SourceRange(IDLoc, - SourceLocation::getFromPointer( - IDLoc.getPointer() + IDInfo->getLength())); - return StmtError(); - } - - QualType Type = C.IntegerTy; - if (auto Prev = LookupIdentifier(IDInfo)) { - auto VD = dyn_cast<VarDecl>(Prev); - if(VD && VD->isUnusedSymbol()) { - Type = VD->getType(); - CurContext->removeDecl(VD); - } else { - Diags.Report(IDLoc, diag::err_redefinition) << IDInfo; - Diags.Report(Prev->getLocation(), diag::note_previous_definition); - return StmtError(); - } - } - - auto Decl = IntrinsicFunctionDecl::Create(C, CurContext, IDLoc, IDInfo, - Type, FuncResult.Function); - CurContext->addDecl(Decl); + ActOnIntrinsicEntityDecl(C, QualType(), IDLoc, IDInfo); auto Result = IntrinsicStmt::Create(C, IDLoc, IDInfo, StmtLabel); if(StmtLabel) DeclareStatementLabel(StmtLabel, Result); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index b20dd50316..bf7ffda47d 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -89,16 +89,252 @@ void Sema::ActOnTypeDeclSpec(ASTContext &C, SourceLocation Loc, DS.setRecord(Record); } +void Sema::DiagnoseRedefinition(SourceLocation Loc, const IdentifierInfo *IDInfo, + Decl *Prev) { + Diags.Report(Loc, diag::err_redefinition) << IDInfo; + Diags.Report(Prev->getLocation(), diag::note_previous_definition); +} + bool Sema::CheckDeclaration(const IdentifierInfo *IDInfo, SourceLocation IDLoc) { if(!IDInfo) return false; if (auto Prev = LookupIdentifier(IDInfo)) { - Diags.Report(IDLoc, diag::err_redefinition) << IDInfo; - Diags.Report(Prev->getLocation(), diag::note_previous_definition); + DiagnoseRedefinition(IDLoc, IDInfo, Prev); return false; } return true; } +// +// Type construction +// + +/// \brief Convert the specified DeclSpec to the appropriate type object. +QualType Sema::ActOnTypeName(ASTContext &C, DeclSpec &DS) { + QualType Result; + switch (DS.getTypeSpecType()) { + case DeclSpec::TST_integer: + Result = C.IntegerTy; + break; + case DeclSpec::TST_unspecified: // FIXME: Correct? + case DeclSpec::TST_real: + Result = C.RealTy; + break; + case DeclSpec::TST_character: + Result = C.CharacterTy; + break; + case DeclSpec::TST_logical: + Result = C.LogicalTy; + break; + case DeclSpec::TST_complex: + Result = C.ComplexTy; + break; + case DeclSpec::TST_struct: + if(!DS.getRecord()) + Result = C.RealTy; + else + Result = C.getRecordType(DS.getRecord()); + break; + } + + if (!DS.hasAttributes()) + return Result; + + const Type *TypeNode = Result.getTypePtr(); + Qualifiers Quals = Qualifiers::fromOpaqueValue(DS.getAttributeSpecs()); + Quals.setIntentAttr(DS.getIntentSpec()); + Quals.setAccessAttr(DS.getAccessSpec()); + + unsigned Kind = BuiltinType::NoKind; + if(DS.isDoublePrecision()) { + assert(!DS.getKindSelector()); + Kind = BuiltinType::Real8; + } else if(DS.hasKindSelector()) + Kind = EvalAndCheckTypeKind(Result, DS.getKindSelector()); + + unsigned LengthSelector = 0; + if(DS.hasLengthSelector() && !DS.isStarLengthSelector()) + LengthSelector = EvalAndCheckCharacterLength(DS.getLengthSelector()); + + Result = C.getExtQualType(TypeNode, Quals, Kind, + DS.isDoublePrecision(), + DS.isStarLengthSelector(), + LengthSelector); + + if (!Quals.hasAttributeSpec(Qualifiers::AS_dimension)) + return Result; + + return ActOnArraySpec(C, Result, DS.getDimensions()); +} + + +// +// Entity declarations. +// + +Decl *Sema::ActOnExternalEntityDecl(ASTContext &C, QualType T, + SourceLocation IDLoc, const IdentifierInfo *IDInfo) { + SourceLocation TypeLoc; + VarDecl *ArgumentExternal = nullptr; + if (auto Prev = LookupIdentifier(IDInfo)) { + // apply EXTERNAL to an unused symbol or an argument. + auto VD = dyn_cast<VarDecl>(Prev); + if(VD && (VD->isUnusedSymbol() || VD->isArgument()) ) { + T = VD->getType(); + TypeLoc = VD->getLocation(); + CurContext->removeDecl(VD); + if(VD->isArgument()) + ArgumentExternal = VD; + } else { + DiagnoseRedefinition(IDLoc, IDInfo, Prev); + return nullptr; + } + } + + DeclarationNameInfo DeclName(IDInfo,IDLoc); + auto Decl = FunctionDecl::Create(C, ArgumentExternal? FunctionDecl::ExternalArgument : + FunctionDecl::External, + CurContext, DeclName, T); + if(!T.isNull()) + SetFunctionType(Decl, T, TypeLoc, SourceRange()); //FIXME: proper loc, and range + CurContext->addDecl(Decl); + if(ArgumentExternal) + ArgumentExternal->setType(C.getFunctionType(Decl)); + return Decl; +} + +Decl *Sema::ActOnIntrinsicEntityDecl(ASTContext &C, QualType T, + SourceLocation IDLoc, const IdentifierInfo *IDInfo) { + auto FuncResult = IntrinsicFunctionMapping.Resolve(IDInfo); + if(FuncResult.IsInvalid) { + Diags.Report(IDLoc, diag::err_intrinsic_invalid_func) + << IDInfo << getTokenRange(IDLoc); + return nullptr; + } + + QualType Type = T.isNull()? C.RealTy : T; + if (auto Prev = LookupIdentifier(IDInfo)) { + auto VD = dyn_cast<VarDecl>(Prev); + if(VD && VD->isUnusedSymbol()) { + Type = VD->getType(); + CurContext->removeDecl(VD); + } else { + DiagnoseRedefinition(IDLoc, IDInfo, Prev); + return nullptr; + } + } + + auto Decl = IntrinsicFunctionDecl::Create(C, CurContext, IDLoc, IDInfo, + Type, FuncResult.Function); + CurContext->addDecl(Decl); + return Decl; +} + +// FIXME: +Decl *Sema::ActOnParameterEntityDecl(ASTContext &C, QualType T, + SourceLocation IDLoc, const IdentifierInfo *IDInfo, + SourceLocation EqualLoc, ExprResult Value) { + VarDecl *VD = nullptr; + + if (auto Prev = LookupIdentifier(IDInfo)) { + VD = dyn_cast<VarDecl>(Prev); + if(!VD || VD->isParameter() || VD->isArgument() || + VD->isFunctionResult()) { + DiagnoseRedefinition(IDLoc, IDInfo, Prev); + return nullptr; + } + } + + // Make sure the value is a constant expression. + if(!Value.get()->isEvaluatable(C)) { + llvm::SmallVector<const Expr*, 16> Results; + Value.get()->GatherNonEvaluatableExpressions(C, Results); + Diags.Report(IDLoc, diag::err_parameter_requires_const_init) + << IDInfo << Value.get()->getSourceRange(); + for(auto E : Results) { + Diags.Report(E->getLocation(), diag::note_parameter_value_invalid_expr) + << E->getSourceRange(); + } + return nullptr; + } + + if(VD) { + Value = TypecheckAssignment(VD->getType(), Value, + EqualLoc, + getTokenRange(IDLoc), + Value.get()->getSourceRange()); + if(Value.isInvalid()) return nullptr; + // FIXME: if value is invalid, mutate into parameter givin a zero value + VD->MutateIntoParameter(Value.get()); + } else { + QualType T = Value.get()->getType(); + VD = VarDecl::Create(C, CurContext, IDLoc, IDInfo, T); + VD->MutateIntoParameter(Value.get()); + CurContext->addDecl(VD); + } + return VD; +} + +Decl *Sema::ActOnEntityDecl(ASTContext &C, const QualType &T, + SourceLocation IDLoc, const IdentifierInfo *IDInfo) { + auto Ext = T.getExtQualsPtrOrNull(); + Qualifiers Quals(Ext? Ext->getQualifiers() : Qualifiers()); + + if(Quals.hasAttributeSpec(Qualifiers::AS_external)) + return ActOnExternalEntityDecl(C, T, IDLoc, IDInfo); + else if(Quals.hasAttributeSpec(Qualifiers::AS_intrinsic)) + return ActOnIntrinsicEntityDecl(C, T, IDLoc, IDInfo); + + if (auto Prev = LookupIdentifier(IDInfo)) { + FunctionDecl *FD = dyn_cast<FunctionDecl>(Prev); + if(auto VD = dyn_cast<VarDecl>(Prev)) { + if(VD->isArgument() && VD->getType().isNull()) { + VD->setType(T); + return VD; + } else if(VD->isFunctionResult()) + FD = CurrentContextAsFunction(); + } + + if(FD && (FD->isNormalFunction() || FD->isExternal())) { + if(FD->getType().isNull()) { + SetFunctionType(FD, T, IDLoc, SourceRange()); //Fixme: proper loc and range + return FD; + } else { + Diags.Report(IDLoc, diag::err_func_return_type_already_specified) << IDInfo; + return nullptr; + } + } + Diags.Report(IDLoc, diag::err_redefinition) << IDInfo; + Diags.Report(Prev->getLocation(), diag::note_previous_definition); + return nullptr; + } + + VarDecl *VD = VarDecl::Create(C, CurContext, IDLoc, IDInfo, T); + CurContext->addDecl(VD); + + if(!T.isNull()) { + auto SubT = T; + if(T->isArrayType()) { + CheckArrayTypeDeclarationCompability(T->asArrayType(), VD); + SubT = T->asArrayType()->getElementType(); + VD->MarkUsedAsVariable(IDLoc); + } + else if(SubT->isCharacterType()) + CheckCharacterLengthDeclarationCompability(SubT, VD); + } + + return VD; +} + +Decl *Sema::ActOnEntityDecl(ASTContext &C, DeclSpec &DS, SourceLocation IDLoc, + const IdentifierInfo *IDInfo) { + QualType T = ActOnTypeName(C, DS); + return ActOnEntityDecl(C, T, IDLoc, IDInfo); +} + +// +// derived types +// + RecordDecl *Sema::ActOnDerivedTypeDecl(ASTContext &C, SourceLocation Loc, SourceLocation IDLoc, const IdentifierInfo* IDInfo) { diff --git a/test/Sema/declarationAttributes.f95 b/test/Sema/declarationAttributes.f95 index ecda50b11c..f64dc50379 100644 --- a/test/Sema/declarationAttributes.f95 +++ b/test/Sema/declarationAttributes.f95 @@ -1,9 +1,13 @@ ! RUN: %flang -fsyntax-only -verify < %s +! RUN: %flang -fsyntax-only -verify -ast-print %s 2>&1 | %file_check %s program declAttrTest implicit none - real, external :: sub + + real, external :: sub ! CHECK: real subroutine sub() + logical, intrinsic :: lle + integer, dimension(10,10) :: i_mat real, dimension(10) :: m(20), k @@ -11,8 +15,9 @@ program declAttrTest integer, dimension(20), & dimension(40) :: vector ! expected-error {{duplicate 'dimension' attribute specifier}} + if(lle('a','b')) then + end if - - ! FIXME: apply the attributes. + ! FIXME: support other attributes. end |