summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorarphaman <arphaman@gmail.com>2013-09-15 12:50:50 +0100
committerarphaman <arphaman@gmail.com>2013-09-15 12:50:50 +0100
commit2cf3fb6ca004470326987a6392555082945d0b36 (patch)
tree1f0670d0ef349bccd1f93b447ca2b3e0dff60977
parentf9193d5550ca1ab9e801d1f2e5ab3d49dba1b0d0 (diff)
downloadflang-2cf3fb6ca004470326987a6392555082945d0b36.tar.gz
improved sema for declaration attributes
-rw-r--r--include/flang/Sema/Sema.h21
-rw-r--r--lib/Sema/Sema.cpp200
-rw-r--r--lib/Sema/SemaDecl.cpp240
-rw-r--r--test/Sema/declarationAttributes.f9511
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